From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- vcl/AllLangMoTarget_vcl.mk | 11 + vcl/CppunitTest_vcl_apitests.mk | 64 + vcl/CppunitTest_vcl_app_test.mk | 32 + vcl/CppunitTest_vcl_backend_test.mk | 50 + vcl/CppunitTest_vcl_bitmap_render_test.mk | 48 + vcl/CppunitTest_vcl_bitmap_test.mk | 64 + vcl/CppunitTest_vcl_bitmapprocessor_test.mk | 55 + vcl/CppunitTest_vcl_blocklistparser_test.mk | 45 + vcl/CppunitTest_vcl_complextext.mk | 55 + vcl/CppunitTest_vcl_dialogs_test.mk | 68 + vcl/CppunitTest_vcl_errorhandler.mk | 49 + vcl/CppunitTest_vcl_filter_ipdf.mk | 49 + vcl/CppunitTest_vcl_filters_test.mk | 53 + vcl/CppunitTest_vcl_font.mk | 49 + vcl/CppunitTest_vcl_fontcharmap.mk | 49 + vcl/CppunitTest_vcl_fontfeature.mk | 51 + vcl/CppunitTest_vcl_fontmetric.mk | 55 + vcl/CppunitTest_vcl_gen.mk | 43 + vcl/CppunitTest_vcl_graphic_test.mk | 57 + vcl/CppunitTest_vcl_jpeg_read_write_test.mk | 51 + vcl/CppunitTest_vcl_lifecycle.mk | 60 + vcl/CppunitTest_vcl_mnemonic.mk | 49 + vcl/CppunitTest_vcl_outdev.mk | 50 + vcl/CppunitTest_vcl_pdfexport.mk | 48 + vcl/CppunitTest_vcl_png_test.mk | 54 + vcl/CppunitTest_vcl_svm_test.mk | 59 + vcl/CppunitTest_vcl_timer.mk | 48 + vcl/CppunitTest_vcl_type_serializer_test.mk | 47 + ...ppunitTest_vcl_widget_definition_reader_test.mk | 52 + vcl/CustomTarget_gtk3_kde5_moc.mk | 24 + vcl/CustomTarget_kf5_moc.mk | 23 + vcl/CustomTarget_nativecalc.mk | 18 + vcl/CustomTarget_nativecore.mk | 18 + vcl/CustomTarget_nativedraw.mk | 18 + vcl/CustomTarget_nativemath.mk | 18 + vcl/CustomTarget_nativewriter.mk | 18 + vcl/CustomTarget_qt5_moc.mk | 33 + vcl/Executable_602fuzzer.mk | 48 + vcl/Executable_bmpfuzzer.mk | 47 + vcl/Executable_cgmfuzzer.mk | 48 + vcl/Executable_diffuzzer.mk | 48 + vcl/Executable_docxfuzzer.mk | 50 + vcl/Executable_dxffuzzer.mk | 47 + vcl/Executable_epsfuzzer.mk | 47 + vcl/Executable_fftester.mk | 39 + vcl/Executable_fodpfuzzer.mk | 50 + vcl/Executable_fodsfuzzer.mk | 50 + vcl/Executable_fodtfuzzer.mk | 50 + vcl/Executable_giffuzzer.mk | 47 + vcl/Executable_htmlfuzzer.mk | 50 + vcl/Executable_hwpfuzzer.mk | 48 + vcl/Executable_icontest.mk | 67 + vcl/Executable_jpgfuzzer.mk | 47 + vcl/Executable_lo_kde5filepicker.mk | 94 + vcl/Executable_lwpfuzzer.mk | 48 + vcl/Executable_metfuzzer.mk | 47 + vcl/Executable_mmlfuzzer.mk | 50 + vcl/Executable_mtfdemo.mk | 54 + vcl/Executable_mtpfuzzer.mk | 48 + vcl/Executable_olefuzzer.mk | 47 + vcl/Executable_pcdfuzzer.mk | 47 + vcl/Executable_pctfuzzer.mk | 47 + vcl/Executable_pcxfuzzer.mk | 47 + vcl/Executable_pngfuzzer.mk | 47 + vcl/Executable_ppmfuzzer.mk | 47 + vcl/Executable_pptfuzzer.mk | 48 + vcl/Executable_pptxfuzzer.mk | 50 + vcl/Executable_psdfuzzer.mk | 47 + vcl/Executable_qpwfuzzer.mk | 48 + vcl/Executable_rasfuzzer.mk | 47 + vcl/Executable_rtffuzzer.mk | 48 + vcl/Executable_scrtffuzzer.mk | 48 + vcl/Executable_sftfuzzer.mk | 47 + vcl/Executable_slkfuzzer.mk | 48 + vcl/Executable_svdemo.mk | 38 + vcl/Executable_svmfuzzer.mk | 47 + vcl/Executable_svpclient.mk | 42 + vcl/Executable_svptest.mk | 38 + vcl/Executable_tgafuzzer.mk | 47 + vcl/Executable_tiffuzzer.mk | 47 + vcl/Executable_ui-previewer.mk | 54 + vcl/Executable_vcldemo.mk | 68 + vcl/Executable_visualbackendtest.mk | 56 + vcl/Executable_wksfuzzer.mk | 50 + vcl/Executable_wmffuzzer.mk | 47 + vcl/Executable_ww2fuzzer.mk | 48 + vcl/Executable_ww6fuzzer.mk | 48 + vcl/Executable_ww8fuzzer.mk | 48 + vcl/Executable_xbmfuzzer.mk | 47 + vcl/Executable_xlsfuzzer.mk | 50 + vcl/Executable_xlsxfuzzer.mk | 50 + vcl/Executable_xpmfuzzer.mk | 47 + vcl/IwyuFilter_vcl.yaml | 128 + vcl/Library_desktop_detector.mk | 72 + vcl/Library_vcl.mk | 736 + vcl/Library_vclplug_gen.mk | 161 + vcl/Library_vclplug_gtk3.mk | 124 + vcl/Library_vclplug_gtk3_kde5.mk | 130 + vcl/Library_vclplug_kf5.mk | 92 + vcl/Library_vclplug_osx.mk | 153 + vcl/Library_vclplug_qt5.mk | 131 + vcl/Library_vclplug_win.mk | 109 + vcl/Makefile | 14 + vcl/Module_vcl.mk | 255 + vcl/Package_fontunxppds.mk | 25 + vcl/Package_fontunxpsprint.mk | 25 + vcl/Package_opengl_blacklist.mk | 16 + vcl/Package_opengl_shader.mk | 41 + vcl/Package_osxres.mk | 18 + vcl/Package_skia_blacklist.mk | 16 + vcl/Package_theme_definitions.mk | 57 + vcl/Package_tipoftheday.mk | 20 + vcl/README | 242 + vcl/README.GDIMetaFile | 190 + vcl/README.lifecycle | 325 + vcl/README.scheduler | 394 + vcl/README.vars | 52 + vcl/StaticLibrary_fuzzer_calc.mk | 25 + vcl/StaticLibrary_fuzzer_core.mk | 25 + vcl/StaticLibrary_fuzzer_draw.mk | 25 + vcl/StaticLibrary_fuzzer_math.mk | 25 + vcl/StaticLibrary_fuzzer_writer.mk | 25 + vcl/StaticLibrary_fuzzerstubs.mk | 47 + vcl/StaticLibrary_glxtest.mk | 41 + vcl/StaticLibrary_vclmain.mk | 42 + vcl/UIConfig_vcl.mk | 34 + vcl/WinResTarget_vcl.mk | 97 + vcl/android/androidinst.cxx | 250 + vcl/backendtest/VisualBackendTest.cxx | 690 + vcl/backendtest/outputdevice/bitmap.cxx | 193 + vcl/backendtest/outputdevice/clip.cxx | 83 + vcl/backendtest/outputdevice/common.cxx | 478 + vcl/backendtest/outputdevice/gradient.cxx | 43 + vcl/backendtest/outputdevice/line.cxx | 200 + vcl/backendtest/outputdevice/outputdevice.cxx | 95 + vcl/backendtest/outputdevice/pixel.cxx | 56 + vcl/backendtest/outputdevice/polygon.cxx | 157 + vcl/backendtest/outputdevice/polyline.cxx | 139 + vcl/backendtest/outputdevice/polyline_b2d.cxx | 127 + vcl/backendtest/outputdevice/polypolygon.cxx | 72 + vcl/backendtest/outputdevice/polypolygon_b2d.cxx | 70 + vcl/backendtest/outputdevice/rectangle.cxx | 114 + vcl/commonfuzzer.mk | 172 + vcl/headless/CustomWidgetDraw.cxx | 421 + vcl/headless/headlessinst.cxx | 101 + vcl/headless/svpbmp.cxx | 283 + vcl/headless/svpcairotextrender.cxx | 40 + vcl/headless/svpdata.cxx | 33 + vcl/headless/svpdummies.cxx | 58 + vcl/headless/svpframe.cxx | 502 + vcl/headless/svpgdi.cxx | 2622 +++ vcl/headless/svpinst.cxx | 627 + vcl/headless/svpprn.cxx | 269 + vcl/headless/svptext.cxx | 121 + vcl/headless/svpvd.cxx | 148 + vcl/inc/BitmapColorizeFilter.hxx | 34 + vcl/inc/BitmapDisabledImageFilter.hxx | 26 + vcl/inc/BitmapFastScaleFilter.hxx | 36 + vcl/inc/BitmapInterpolateScaleFilter.hxx | 35 + vcl/inc/BitmapLightenFilter.hxx | 24 + vcl/inc/BitmapScaleConvolutionFilter.hxx | 78 + vcl/inc/BitmapScaleSuperFilter.hxx | 41 + vcl/inc/BitmapSymmetryCheck.hxx | 31 + vcl/inc/ControlCacheKey.hxx | 94 + vcl/inc/FileDefinitionWidgetDraw.hxx | 61 + vcl/inc/IconThemeScanner.hxx | 92 + vcl/inc/IconThemeSelector.hxx | 97 + vcl/inc/OptionalBox.hxx | 42 + vcl/inc/PhysicalFontCollection.hxx | 96 + vcl/inc/PhysicalFontFace.hxx | 78 + vcl/inc/PhysicalFontFamily.hxx | 101 + vcl/inc/ResampleKernel.hxx | 116 + vcl/inc/SalGradient.hxx | 36 + vcl/inc/TypeSerializer.hxx | 52 + vcl/inc/WidgetDrawInterface.hxx | 126 + vcl/inc/WidgetThemeLibrary.hxx | 159 + vcl/inc/WidgetThemeLibraryTypes.hxx | 235 + vcl/inc/accel.h | 41 + vcl/inc/accmgr.hxx | 53 + vcl/inc/android/androidinst.hxx | 48 + vcl/inc/android/svsys.h | 17 + vcl/inc/backend/BackendCapabilities.hxx | 28 + vcl/inc/bitmap/Octree.hxx | 82 + vcl/inc/bitmap/ScanlineTools.hxx | 236 + vcl/inc/bitmap/impoctree.hxx | 109 + vcl/inc/bitmaps.hlst | 228 + vcl/inc/bitmapwriteaccess.hxx | 94 + vcl/inc/bmpfast.hxx | 45 + vcl/inc/brdwin.hxx | 294 + vcl/inc/canvasbitmap.hxx | 121 + vcl/inc/configsettings.hxx | 66 + vcl/inc/controldata.hxx | 38 + vcl/inc/cursor_hotspots.hxx | 169 + vcl/inc/dbggui.hxx | 29 + vcl/inc/debugevent.hxx | 36 + vcl/inc/displayconnectiondispatch.hxx | 63 + vcl/inc/dndeventdispatcher.hxx | 111 + vcl/inc/dndlistenercontainer.hxx | 112 + vcl/inc/driverblocklist.hxx | 176 + vcl/inc/factory.hxx | 79 + vcl/inc/fltcall.hxx | 37 + vcl/inc/font/FeatureCollector.hxx | 55 + vcl/inc/font/OpenTypeFeatureDefinitionList.hxx | 48 + vcl/inc/font/OpenTypeFeatureStrings.hrc | 106 + vcl/inc/fontattributes.hxx | 126 + vcl/inc/fontinstance.hxx | 126 + vcl/inc/fontselect.hxx | 83 + vcl/inc/fontsubset.hxx | 94 + vcl/inc/graphic/DetectorTools.hxx | 61 + vcl/inc/graphic/GraphicFormatDetector.hxx | 76 + vcl/inc/graphic/GraphicID.hxx | 47 + vcl/inc/graphic/GraphicReader.hxx | 40 + vcl/inc/graphic/Manager.hxx | 76 + vcl/inc/graphic/UnoGraphic.hxx | 82 + vcl/inc/graphic/UnoGraphicDescriptor.hxx | 121 + vcl/inc/graphic/UnoGraphicTransformer.hxx | 58 + vcl/inc/headless/CustomWidgetDraw.hxx | 56 + vcl/inc/headless/svpbmp.hxx | 89 + vcl/inc/headless/svpcairotextrender.hxx | 32 + vcl/inc/headless/svpdummies.hxx | 64 + vcl/inc/headless/svpframe.hxx | 124 + vcl/inc/headless/svpgdi.hxx | 287 + vcl/inc/headless/svpinst.hxx | 195 + vcl/inc/headless/svpprn.hxx | 39 + vcl/inc/headless/svpvd.hxx | 68 + vcl/inc/helpwin.hxx | 84 + vcl/inc/hyperlabel.hxx | 71 + vcl/inc/iconview.hxx | 39 + vcl/inc/image.h | 72 + vcl/inc/imagerepository.hxx | 59 + vcl/inc/impanmvw.hxx | 98 + vcl/inc/impdel.hxx | 80 + vcl/inc/impfont.hxx | 137 + vcl/inc/impfontcache.hxx | 99 + vcl/inc/impfontcharmap.hxx | 58 + vcl/inc/impfontmetricdata.hxx | 149 + vcl/inc/impglyphitem.hxx | 140 + vcl/inc/impgraph.hxx | 214 + vcl/inc/implimagetree.hxx | 158 + vcl/inc/ios/iosinst.hxx | 51 + vcl/inc/ios/svsys.h | 17 + vcl/inc/jobdata.hxx | 87 + vcl/inc/jobset.h | 112 + vcl/inc/jsdialog/jsdialogbuilder.hxx | 133 + vcl/inc/langboost.hxx | 18 + vcl/inc/listbox.hxx | 608 + vcl/inc/messagedialog.hxx | 58 + vcl/inc/opengl/BufferObject.hxx | 84 + vcl/inc/opengl/DeviceInfo.hxx | 23 + vcl/inc/opengl/FixedTextureAtlas.hxx | 47 + vcl/inc/opengl/LineRenderUtils.hxx | 55 + vcl/inc/opengl/PackedTextureAtlas.hxx | 57 + vcl/inc/opengl/RenderList.hxx | 173 + vcl/inc/opengl/RenderState.hxx | 188 + vcl/inc/opengl/TextureState.hxx | 76 + vcl/inc/opengl/VertexUtils.hxx | 120 + vcl/inc/opengl/framebuffer.hxx | 48 + vcl/inc/opengl/gdiimpl.hxx | 395 + vcl/inc/opengl/program.hxx | 122 + vcl/inc/opengl/salbmp.hxx | 113 + vcl/inc/opengl/texture.hxx | 139 + vcl/inc/opengl/win/WinDeviceInfo.hxx | 103 + vcl/inc/opengl/win/gdiimpl.hxx | 97 + vcl/inc/opengl/win/winlayout.hxx | 51 + vcl/inc/opengl/x11/X11DeviceInfo.hxx | 75 + vcl/inc/opengl/x11/cairotextrender.hxx | 27 + vcl/inc/opengl/x11/gdiimpl.hxx | 42 + vcl/inc/opengl/x11/glxtest.hxx | 21 + vcl/inc/opengl/x11/salvd.hxx | 57 + vcl/inc/opengl/zone.hxx | 46 + vcl/inc/osx/a11yfactory.h | 42 + vcl/inc/osx/a11yfocustracker.hxx | 103 + vcl/inc/osx/a11ylistener.hxx | 53 + vcl/inc/osx/a11ywrapper.h | 110 + vcl/inc/osx/keyboardfocuslistener.hxx | 37 + vcl/inc/osx/osxvcltypes.h | 30 + vcl/inc/osx/printview.h | 63 + vcl/inc/osx/runinmain.hxx | 175 + vcl/inc/osx/saldata.hxx | 111 + vcl/inc/osx/salframe.h | 224 + vcl/inc/osx/salframeview.h | 213 + vcl/inc/osx/salinst.h | 162 + vcl/inc/osx/salmenu.h | 112 + vcl/inc/osx/salnativewidgets.h | 70 + vcl/inc/osx/salnsmenu.h | 53 + vcl/inc/osx/salnstimer.h | 35 + vcl/inc/osx/salobj.h | 68 + vcl/inc/osx/salprn.h | 152 + vcl/inc/osx/salsys.h | 44 + vcl/inc/osx/saltimer.h | 75 + vcl/inc/osx/svsys.h | 29 + vcl/inc/osx/vclnsapp.h | 68 + vcl/inc/outdata.hxx | 32 + vcl/inc/outdev.h | 144 + vcl/inc/pch/precompiled_vcl.cxx | 12 + vcl/inc/pch/precompiled_vcl.hxx | 340 + vcl/inc/pdf/BitmapID.hxx | 44 + vcl/inc/pdf/Matrix3.hxx | 54 + vcl/inc/pdf/ResourceDict.hxx | 42 + vcl/inc/pdf/XmpMetadata.hxx | 51 + vcl/inc/ppdparser.hxx | 274 + vcl/inc/print.h | 73 + vcl/inc/print.hrc | 115 + vcl/inc/printaccessoryview.hrc | 36 + vcl/inc/printdlg.hxx | 292 + vcl/inc/printerinfomanager.hxx | 175 + vcl/inc/qt5/Qt5AccessibleEventListener.hxx | 38 + vcl/inc/qt5/Qt5AccessibleWidget.hxx | 144 + vcl/inc/qt5/Qt5Bitmap.hxx | 66 + vcl/inc/qt5/Qt5Clipboard.hxx | 97 + vcl/inc/qt5/Qt5Data.hxx | 47 + vcl/inc/qt5/Qt5DragAndDrop.hxx | 115 + vcl/inc/qt5/Qt5FilePicker.hxx | 175 + vcl/inc/qt5/Qt5Font.hxx | 41 + vcl/inc/qt5/Qt5FontFace.hxx | 67 + vcl/inc/qt5/Qt5Frame.hxx | 225 + vcl/inc/qt5/Qt5Graphics.hxx | 202 + vcl/inc/qt5/Qt5GraphicsBase.hxx | 30 + vcl/inc/qt5/Qt5Graphics_Controls.hxx | 97 + vcl/inc/qt5/Qt5Instance.hxx | 161 + vcl/inc/qt5/Qt5MainWindow.hxx | 40 + vcl/inc/qt5/Qt5Menu.hxx | 122 + vcl/inc/qt5/Qt5Object.hxx | 79 + vcl/inc/qt5/Qt5OpenGLContext.hxx | 50 + vcl/inc/qt5/Qt5Painter.hxx | 67 + vcl/inc/qt5/Qt5Printer.hxx | 32 + vcl/inc/qt5/Qt5SvpGraphics.hxx | 55 + vcl/inc/qt5/Qt5SvpSurface.hxx | 44 + vcl/inc/qt5/Qt5System.hxx | 23 + vcl/inc/qt5/Qt5Timer.hxx | 47 + vcl/inc/qt5/Qt5Tools.hxx | 154 + vcl/inc/qt5/Qt5Transferable.hxx | 124 + vcl/inc/qt5/Qt5VirtualDevice.hxx | 56 + vcl/inc/qt5/Qt5Widget.hxx | 103 + vcl/inc/qt5/Qt5XAccessible.hxx | 34 + vcl/inc/quartz/CGHelpers.hxx | 105 + vcl/inc/quartz/common.h | 51 + vcl/inc/quartz/ctfonts.hxx | 31 + vcl/inc/quartz/salbmp.h | 105 + vcl/inc/quartz/salgdi.h | 425 + vcl/inc/quartz/salgdicommon.hxx | 111 + vcl/inc/quartz/salvd.h | 73 + vcl/inc/quartz/utils.h | 50 + vcl/inc/regband.hxx | 129 + vcl/inc/regionband.hxx | 82 + vcl/inc/salbmp.hxx | 125 + vcl/inc/saldatabasic.hxx | 67 + vcl/inc/salframe.hxx | 311 + vcl/inc/salgdi.hxx | 638 + vcl/inc/salgdiimpl.hxx | 211 + vcl/inc/salgeom.hxx | 72 + vcl/inc/salinst.hxx | 223 + vcl/inc/sallayout.hxx | 226 + vcl/inc/salmenu.hxx | 102 + vcl/inc/salobj.hxx | 79 + vcl/inc/salprn.hxx | 122 + vcl/inc/salptype.hxx | 52 + vcl/inc/salsession.hxx | 113 + vcl/inc/salsys.hxx | 90 + vcl/inc/saltimer.hxx | 103 + vcl/inc/salusereventlist.hxx | 122 + vcl/inc/salvd.hxx | 58 + vcl/inc/salvtables.hxx | 1105 ++ vcl/inc/salwtype.hxx | 274 + vcl/inc/scanlinewriter.hxx | 90 + vcl/inc/schedulerimpl.hxx | 70 + vcl/inc/scrptrun.h | 158 + vcl/inc/scrwnd.hxx | 82 + vcl/inc/sft.hxx | 752 + vcl/inc/skia/gdiimpl.hxx | 332 + vcl/inc/skia/salbmp.hxx | 134 + vcl/inc/skia/utils.hxx | 135 + vcl/inc/skia/win/gdiimpl.hxx | 102 + vcl/inc/skia/x11/gdiimpl.hxx | 48 + vcl/inc/skia/x11/salvd.hxx | 46 + vcl/inc/skia/x11/textrender.hxx | 40 + vcl/inc/skia/zone.hxx | 30 + vcl/inc/slider.hxx | 103 + vcl/inc/spin.hxx | 43 + vcl/inc/strhelper.hxx | 72 + vcl/inc/strings.hrc | 158 + vcl/inc/strings.hxx | 17 + vcl/inc/svdata.hxx | 462 + vcl/inc/svimpbox.hxx | 398 + vcl/inc/svmconverter.hxx | 90 + vcl/inc/svsys.h | 41 + vcl/inc/test/outputdevice.hxx | 223 + vcl/inc/textlayout.hxx | 112 + vcl/inc/textlineinfo.hxx | 71 + vcl/inc/textrender.hxx | 74 + vcl/inc/toolbox.h | 158 + vcl/inc/treeglue.hxx | 174 + vcl/inc/uiobject-internal.hxx | 34 + vcl/inc/units.hrc | 62 + vcl/inc/unx/XIM.h | 111 + vcl/inc/unx/cairotextrender.hxx | 42 + vcl/inc/unx/cpdmgr.hxx | 126 + vcl/inc/unx/cupsmgr.hxx | 90 + vcl/inc/unx/desktops.hxx | 40 + vcl/inc/unx/fc_fontoptions.hxx | 43 + vcl/inc/unx/fontmanager.hxx | 322 + vcl/inc/unx/freetype_glyphcache.hxx | 127 + vcl/inc/unx/freetypetextrender.hxx | 75 + vcl/inc/unx/gendata.hxx | 102 + vcl/inc/unx/gendisp.hxx | 55 + vcl/inc/unx/geninst.h | 84 + vcl/inc/unx/genprn.h | 94 + vcl/inc/unx/genpspgraphics.h | 213 + vcl/inc/unx/gensys.h | 50 + vcl/inc/unx/glyphcache.hxx | 174 + vcl/inc/unx/gstsink.hxx | 27 + vcl/inc/unx/gtk/atkbridge.hxx | 30 + vcl/inc/unx/gtk/gloactiongroup.h | 78 + vcl/inc/unx/gtk/glomenu.h | 137 + vcl/inc/unx/gtk/gtkbackend.hxx | 25 + vcl/inc/unx/gtk/gtkdata.hxx | 152 + vcl/inc/unx/gtk/gtkframe.hxx | 567 + vcl/inc/unx/gtk/gtkgdi.hxx | 399 + vcl/inc/unx/gtk/gtkinst.hxx | 298 + vcl/inc/unx/gtk/gtkobject.hxx | 107 + vcl/inc/unx/gtk/gtkprintwrapper.hxx | 69 + vcl/inc/unx/gtk/gtkprn.hxx | 51 + vcl/inc/unx/gtk/gtksalmenu.hxx | 151 + vcl/inc/unx/gtk/gtksys.hxx | 48 + vcl/inc/unx/gtk/hudawareness.h | 32 + vcl/inc/unx/helper.hxx | 54 + vcl/inc/unx/i18n_cb.hxx | 91 + vcl/inc/unx/i18n_ic.hxx | 80 + vcl/inc/unx/i18n_im.hxx | 54 + vcl/inc/unx/i18n_keysym.hxx | 67 + vcl/inc/unx/i18n_xkb.hxx | 67 + vcl/inc/unx/nativewindowhandleprovider.hxx | 25 + vcl/inc/unx/printergfx.hxx | 347 + vcl/inc/unx/printerjob.hxx | 128 + vcl/inc/unx/salbmp.h | 231 + vcl/inc/unx/saldata.hxx | 75 + vcl/inc/unx/saldisp.hxx | 428 + vcl/inc/unx/salframe.h | 270 + vcl/inc/unx/salgdi.h | 340 + vcl/inc/unx/salinst.h | 95 + vcl/inc/unx/salobj.h | 91 + vcl/inc/unx/saltimer.h | 40 + vcl/inc/unx/saltype.h | 26 + vcl/inc/unx/salunx.h | 28 + vcl/inc/unx/salunxtime.h | 80 + vcl/inc/unx/salvd.h | 79 + vcl/inc/unx/screensaverinhibitor.hxx | 71 + vcl/inc/unx/sm.hxx | 81 + vcl/inc/unx/svsys.h | 29 + vcl/inc/unx/wmadaptor.hxx | 302 + vcl/inc/unx/x11/x11cairotextrender.hxx | 46 + vcl/inc/unx/x11/x11gdiimpl.h | 25 + vcl/inc/unx/x11/x11sys.hxx | 44 + vcl/inc/unx/x11/xlimits.hxx | 20 + vcl/inc/unx/x11/xrender_peer.hxx | 165 + vcl/inc/unx/x11_cursors/ase_curs.h | 34 + vcl/inc/unx/x11_cursors/ase_mask.h | 34 + vcl/inc/unx/x11_cursors/asn_curs.h | 34 + vcl/inc/unx/x11_cursors/asn_mask.h | 34 + vcl/inc/unx/x11_cursors/asne_curs.h | 34 + vcl/inc/unx/x11_cursors/asne_mask.h | 34 + vcl/inc/unx/x11_cursors/asns_curs.h | 34 + vcl/inc/unx/x11_cursors/asns_mask.h | 34 + vcl/inc/unx/x11_cursors/asnswe_curs.h | 34 + vcl/inc/unx/x11_cursors/asnswe_mask.h | 34 + vcl/inc/unx/x11_cursors/asnw_curs.h | 34 + vcl/inc/unx/x11_cursors/asnw_mask.h | 34 + vcl/inc/unx/x11_cursors/ass_curs.h | 34 + vcl/inc/unx/x11_cursors/ass_mask.h | 34 + vcl/inc/unx/x11_cursors/asse_curs.h | 34 + vcl/inc/unx/x11_cursors/asse_mask.h | 34 + vcl/inc/unx/x11_cursors/assw_curs.h | 34 + vcl/inc/unx/x11_cursors/assw_mask.h | 34 + vcl/inc/unx/x11_cursors/asw_curs.h | 34 + vcl/inc/unx/x11_cursors/asw_mask.h | 34 + vcl/inc/unx/x11_cursors/aswe_curs.h | 34 + vcl/inc/unx/x11_cursors/aswe_mask.h | 34 + vcl/inc/unx/x11_cursors/chain_curs.h | 34 + vcl/inc/unx/x11_cursors/chain_mask.h | 32 + vcl/inc/unx/x11_cursors/chainnot_curs.h | 34 + vcl/inc/unx/x11_cursors/chainnot_mask.h | 32 + vcl/inc/unx/x11_cursors/chart_curs.h | 34 + vcl/inc/unx/x11_cursors/chart_mask.h | 34 + vcl/inc/unx/x11_cursors/copydata_curs.h | 36 + vcl/inc/unx/x11_cursors/copydata_mask.h | 36 + vcl/inc/unx/x11_cursors/copydlnk_curs.h | 36 + vcl/inc/unx/x11_cursors/copydlnk_mask.h | 36 + vcl/inc/unx/x11_cursors/copyfile_curs.h | 36 + vcl/inc/unx/x11_cursors/copyfile_mask.h | 36 + vcl/inc/unx/x11_cursors/copyfiles_curs.h | 36 + vcl/inc/unx/x11_cursors/copyfiles_mask.h | 36 + vcl/inc/unx/x11_cursors/copyflnk_curs.h | 36 + vcl/inc/unx/x11_cursors/copyflnk_mask.h | 36 + vcl/inc/unx/x11_cursors/crook_curs.h | 36 + vcl/inc/unx/x11_cursors/crook_mask.h | 34 + vcl/inc/unx/x11_cursors/crop_curs.h | 36 + vcl/inc/unx/x11_cursors/crop_mask.h | 34 + vcl/inc/unx/x11_cursors/detective_curs.h | 34 + vcl/inc/unx/x11_cursors/detective_mask.h | 34 + vcl/inc/unx/x11_cursors/drawarc_curs.h | 36 + vcl/inc/unx/x11_cursors/drawarc_mask.h | 34 + vcl/inc/unx/x11_cursors/drawbezier_curs.h | 36 + vcl/inc/unx/x11_cursors/drawbezier_mask.h | 34 + vcl/inc/unx/x11_cursors/drawcaption_curs.h | 36 + vcl/inc/unx/x11_cursors/drawcaption_mask.h | 34 + vcl/inc/unx/x11_cursors/drawcirclecut_curs.h | 36 + vcl/inc/unx/x11_cursors/drawcirclecut_mask.h | 34 + vcl/inc/unx/x11_cursors/drawconnect_curs.h | 36 + vcl/inc/unx/x11_cursors/drawconnect_mask.h | 34 + vcl/inc/unx/x11_cursors/drawellipse_curs.h | 36 + vcl/inc/unx/x11_cursors/drawellipse_mask.h | 34 + vcl/inc/unx/x11_cursors/drawfreehand_curs.h | 36 + vcl/inc/unx/x11_cursors/drawfreehand_mask.h | 34 + vcl/inc/unx/x11_cursors/drawline_curs.h | 36 + vcl/inc/unx/x11_cursors/drawline_mask.h | 34 + vcl/inc/unx/x11_cursors/drawpie_curs.h | 36 + vcl/inc/unx/x11_cursors/drawpie_mask.h | 34 + vcl/inc/unx/x11_cursors/drawpolygon_curs.h | 36 + vcl/inc/unx/x11_cursors/drawpolygon_mask.h | 34 + vcl/inc/unx/x11_cursors/drawrect_curs.h | 36 + vcl/inc/unx/x11_cursors/drawrect_mask.h | 34 + vcl/inc/unx/x11_cursors/drawtext_curs.h | 36 + vcl/inc/unx/x11_cursors/drawtext_mask.h | 34 + vcl/inc/unx/x11_cursors/fill_curs.h | 34 + vcl/inc/unx/x11_cursors/fill_mask.h | 34 + vcl/inc/unx/x11_cursors/hshear_curs.h | 36 + vcl/inc/unx/x11_cursors/hshear_mask.h | 34 + vcl/inc/unx/x11_cursors/invert50.h | 40 + vcl/inc/unx/x11_cursors/linkdata_curs.h | 36 + vcl/inc/unx/x11_cursors/linkdata_mask.h | 36 + vcl/inc/unx/x11_cursors/linkfile_curs.h | 36 + vcl/inc/unx/x11_cursors/linkfile_mask.h | 36 + vcl/inc/unx/x11_cursors/magnify_curs.h | 34 + vcl/inc/unx/x11_cursors/magnify_mask.h | 34 + vcl/inc/unx/x11_cursors/mirror_curs.h | 36 + vcl/inc/unx/x11_cursors/mirror_mask.h | 34 + vcl/inc/unx/x11_cursors/movebezierweight_curs.h | 36 + vcl/inc/unx/x11_cursors/movebezierweight_mask.h | 34 + vcl/inc/unx/x11_cursors/movedata_curs.h | 36 + vcl/inc/unx/x11_cursors/movedata_mask.h | 36 + vcl/inc/unx/x11_cursors/movedlnk_curs.h | 36 + vcl/inc/unx/x11_cursors/movedlnk_mask.h | 36 + vcl/inc/unx/x11_cursors/movefile_curs.h | 36 + vcl/inc/unx/x11_cursors/movefile_mask.h | 36 + vcl/inc/unx/x11_cursors/movefiles_curs.h | 36 + vcl/inc/unx/x11_cursors/movefiles_mask.h | 36 + vcl/inc/unx/x11_cursors/moveflnk_curs.h | 36 + vcl/inc/unx/x11_cursors/moveflnk_mask.h | 36 + vcl/inc/unx/x11_cursors/movepoint_curs.h | 36 + vcl/inc/unx/x11_cursors/movepoint_mask.h | 34 + vcl/inc/unx/x11_cursors/nodrop_curs.h | 36 + vcl/inc/unx/x11_cursors/nodrop_mask.h | 36 + vcl/inc/unx/x11_cursors/null_curs.h | 24 + vcl/inc/unx/x11_cursors/null_mask.h | 22 + vcl/inc/unx/x11_cursors/pivotcol_curs.h | 36 + vcl/inc/unx/x11_cursors/pivotcol_mask.h | 36 + vcl/inc/unx/x11_cursors/pivotdel_curs.h | 36 + vcl/inc/unx/x11_cursors/pivotdel_mask.h | 36 + vcl/inc/unx/x11_cursors/pivotfld_curs.h | 36 + vcl/inc/unx/x11_cursors/pivotfld_mask.h | 36 + vcl/inc/unx/x11_cursors/pivotrow_curs.h | 36 + vcl/inc/unx/x11_cursors/pivotrow_mask.h | 34 + vcl/inc/unx/x11_cursors/rotate_curs.h | 36 + vcl/inc/unx/x11_cursors/rotate_mask.h | 34 + vcl/inc/unx/x11_cursors/salcursors.h | 151 + vcl/inc/unx/x11_cursors/tblsele_curs.h | 29 + vcl/inc/unx/x11_cursors/tblsele_mask.h | 27 + vcl/inc/unx/x11_cursors/tblsels_curs.h | 29 + vcl/inc/unx/x11_cursors/tblsels_mask.h | 27 + vcl/inc/unx/x11_cursors/tblselse_curs.h | 29 + vcl/inc/unx/x11_cursors/tblselse_mask.h | 27 + vcl/inc/unx/x11_cursors/tblselsw_curs.h | 29 + vcl/inc/unx/x11_cursors/tblselsw_mask.h | 27 + vcl/inc/unx/x11_cursors/tblselw_curs.h | 29 + vcl/inc/unx/x11_cursors/tblselw_mask.h | 27 + vcl/inc/unx/x11_cursors/vertcurs_curs.h | 29 + vcl/inc/unx/x11_cursors/vertcurs_mask.h | 29 + vcl/inc/unx/x11_cursors/vshear_curs.h | 36 + vcl/inc/unx/x11_cursors/vshear_mask.h | 34 + vcl/inc/unx/x11_cursors/wshide_curs.h | 29 + vcl/inc/unx/x11_cursors/wshide_mask.h | 29 + vcl/inc/unx/x11_cursors/wsshow_curs.h | 29 + vcl/inc/unx/x11_cursors/wsshow_mask.h | 29 + vcl/inc/vcleventlisteners.hxx | 37 + vcl/inc/vclpluginapi.h | 76 + vcl/inc/vclstatuslistener.hxx | 108 + vcl/inc/wall2.hxx | 50 + vcl/inc/watchdog.hxx | 32 + vcl/inc/widgetdraw/WidgetDefinition.hxx | 298 + vcl/inc/widgetdraw/WidgetDefinitionReader.hxx | 45 + vcl/inc/win/DWriteTextRenderer.hxx | 101 + vcl/inc/win/salbmp.h | 115 + vcl/inc/win/saldata.hxx | 305 + vcl/inc/win/salframe.h | 154 + vcl/inc/win/salgdi.h | 429 + vcl/inc/win/salids.hrc | 93 + vcl/inc/win/salinst.h | 87 + vcl/inc/win/salmenu.h | 68 + vcl/inc/win/salobj.h | 55 + vcl/inc/win/salprn.h | 113 + vcl/inc/win/salsys.h | 70 + vcl/inc/win/saltimer.h | 86 + vcl/inc/win/salvd.h | 70 + vcl/inc/win/scoped_gdi.hxx | 75 + vcl/inc/win/svsys.h | 33 + vcl/inc/win/wincomp.hxx | 234 + vcl/inc/win/wingdiimpl.hxx | 61 + vcl/inc/win/winlayout.hxx | 187 + vcl/inc/window.h | 438 + vcl/inc/wizdlg.hxx | 315 + vcl/ios/DataFlavorMapping.cxx | 571 + vcl/ios/DataFlavorMapping.hxx | 127 + vcl/ios/HtmlFmtFlt.cxx | 172 + vcl/ios/HtmlFmtFlt.hxx | 41 + vcl/ios/clipboard.cxx | 185 + vcl/ios/clipboard.hxx | 111 + vcl/ios/dummies.cxx | 138 + vcl/ios/iOSTransferable.cxx | 186 + vcl/ios/iOSTransferable.hxx | 73 + vcl/ios/iosinst.cxx | 197 + vcl/jsdialog/jsdialogbuilder.cxx | 207 + vcl/null/printerinfomanager.cxx | 120 + vcl/opengl/DeviceInfo.cxx | 16 + vcl/opengl/FixedTextureAtlas.cxx | 137 + vcl/opengl/LineRenderUtils.cxx | 189 + vcl/opengl/PackedTextureAtlas.cxx | 192 + vcl/opengl/README.deprecated | 23 + vcl/opengl/README.opengl | 26 + vcl/opengl/RenderList.cxx | 403 + vcl/opengl/framebuffer.cxx | 108 + vcl/opengl/gdiimpl.cxx | 2315 +++ vcl/opengl/opengl_blacklist_windows.xml | 67 + vcl/opengl/program.cxx | 390 + vcl/opengl/salbmp.cxx | 783 + vcl/opengl/scale.cxx | 423 + .../shaders/areaHashCRC64TFragmentShader.glsl | 87 + .../shaders/areaScaleFastFragmentShader.glsl | 59 + vcl/opengl/shaders/areaScaleFragmentShader.glsl | 239 + .../shaders/blendedTextureFragmentShader.glsl | 33 + vcl/opengl/shaders/blendedTextureVertexShader.glsl | 28 + vcl/opengl/shaders/combinedFragmentShader.glsl | 44 + .../shaders/combinedTextureFragmentShader.glsl | 73 + .../shaders/combinedTextureVertexShader.glsl | 43 + vcl/opengl/shaders/combinedVertexShader.glsl | 76 + vcl/opengl/shaders/convolutionFragmentShader.glsl | 30 + vcl/opengl/shaders/diffTextureFragmentShader.glsl | 30 + vcl/opengl/shaders/dumbVertexShader.glsl | 20 + vcl/opengl/shaders/greyscaleFragmentShader.glsl | 20 + vcl/opengl/shaders/invert50FragmentShader.glsl | 25 + vcl/opengl/shaders/lineFragmentShader.glsl | 38 + vcl/opengl/shaders/lineVertexShader.glsl | 37 + .../shaders/linearGradientFragmentShader.glsl | 23 + vcl/opengl/shaders/maskFragmentShader.glsl | 23 + .../shaders/maskedTextureFragmentShader.glsl | 27 + vcl/opengl/shaders/maskedTextureVertexShader.glsl | 26 + .../shaders/radialGradientFragmentShader.glsl | 23 + vcl/opengl/shaders/replaceColorFragmentShader.glsl | 25 + vcl/opengl/shaders/solidFragmentShader.glsl | 19 + vcl/opengl/shaders/textureFragmentShader.glsl | 20 + vcl/opengl/shaders/textureVertexShader.glsl | 22 + .../shaders/transformedTextureVertexShader.glsl | 28 + vcl/opengl/texture.cxx | 606 + vcl/opengl/win/WinDeviceInfo.cxx | 494 + vcl/opengl/win/gdiimpl.cxx | 898 + vcl/opengl/win/winlayout.cxx | 60 + vcl/opengl/x11/X11DeviceInfo.cxx | 363 + vcl/opengl/x11/cairotextrender.cxx | 84 + vcl/opengl/x11/gdiimpl.cxx | 598 + vcl/opengl/x11/salvd.cxx | 90 + vcl/osx/DataFlavorMapping.cxx | 747 + vcl/osx/DataFlavorMapping.hxx | 129 + vcl/osx/DragActionConversion.cxx | 84 + vcl/osx/DragActionConversion.hxx | 43 + vcl/osx/DragSource.cxx | 338 + vcl/osx/DragSource.hxx | 128 + vcl/osx/DragSourceContext.cxx | 55 + vcl/osx/DragSourceContext.hxx | 53 + vcl/osx/DropTarget.cxx | 548 + vcl/osx/DropTarget.hxx | 157 + vcl/osx/HtmlFmtFlt.cxx | 165 + vcl/osx/HtmlFmtFlt.hxx | 41 + vcl/osx/OSXTransferable.cxx | 192 + vcl/osx/OSXTransferable.hxx | 74 + vcl/osx/PictToBmpFlt.cxx | 72 + vcl/osx/PictToBmpFlt.hxx | 38 + vcl/osx/README.a11y | 7 + vcl/osx/a11yactionwrapper.h | 35 + vcl/osx/a11yactionwrapper.mm | 77 + vcl/osx/a11ycomponentwrapper.h | 39 + vcl/osx/a11ycomponentwrapper.mm | 102 + vcl/osx/a11yfactory.mm | 219 + vcl/osx/a11yfocuslistener.cxx | 82 + vcl/osx/a11yfocuslistener.hxx | 46 + vcl/osx/a11yfocustracker.cxx | 256 + vcl/osx/a11ylistener.cxx | 145 + vcl/osx/a11yrolehelper.h | 35 + vcl/osx/a11yrolehelper.mm | 281 + vcl/osx/a11yselectionwrapper.h | 37 + vcl/osx/a11yselectionwrapper.mm | 88 + vcl/osx/a11ytablewrapper.h | 38 + vcl/osx/a11ytablewrapper.mm | 202 + vcl/osx/a11ytextattributeswrapper.h | 32 + vcl/osx/a11ytextattributeswrapper.mm | 361 + vcl/osx/a11ytextwrapper.h | 58 + vcl/osx/a11ytextwrapper.mm | 296 + vcl/osx/a11yutil.h | 32 + vcl/osx/a11yutil.mm | 46 + vcl/osx/a11yvaluewrapper.h | 40 + vcl/osx/a11yvaluewrapper.mm | 87 + vcl/osx/a11ywrapper.mm | 1147 ++ vcl/osx/a11ywrapperbutton.h | 35 + vcl/osx/a11ywrapperbutton.mm | 54 + vcl/osx/a11ywrappercheckbox.h | 35 + vcl/osx/a11ywrappercheckbox.mm | 58 + vcl/osx/a11ywrappercombobox.h | 44 + vcl/osx/a11ywrappercombobox.mm | 155 + vcl/osx/a11ywrappergroup.h | 34 + vcl/osx/a11ywrappergroup.mm | 49 + vcl/osx/a11ywrapperlist.h | 33 + vcl/osx/a11ywrapperlist.mm | 40 + vcl/osx/a11ywrapperradiobutton.h | 35 + vcl/osx/a11ywrapperradiobutton.mm | 57 + vcl/osx/a11ywrapperradiogroup.h | 33 + vcl/osx/a11ywrapperradiogroup.mm | 40 + vcl/osx/a11ywrapperrow.h | 34 + vcl/osx/a11ywrapperrow.mm | 50 + vcl/osx/a11ywrapperscrollarea.h | 35 + vcl/osx/a11ywrapperscrollarea.mm | 77 + vcl/osx/a11ywrapperscrollbar.h | 33 + vcl/osx/a11ywrapperscrollbar.mm | 43 + vcl/osx/a11ywrappersplitter.h | 33 + vcl/osx/a11ywrappersplitter.mm | 40 + vcl/osx/a11ywrapperstatictext.h | 34 + vcl/osx/a11ywrapperstatictext.mm | 48 + vcl/osx/a11ywrappertabgroup.h | 33 + vcl/osx/a11ywrappertabgroup.mm | 42 + vcl/osx/a11ywrappertextarea.h | 33 + vcl/osx/a11ywrappertextarea.mm | 40 + vcl/osx/a11ywrappertoolbar.h | 33 + vcl/osx/a11ywrappertoolbar.mm | 42 + vcl/osx/clipboard.cxx | 345 + vcl/osx/clipboard.hxx | 152 + vcl/osx/cuidraw.hxx | 47 + vcl/osx/documentfocuslistener.cxx | 214 + vcl/osx/documentfocuslistener.hxx | 100 + vcl/osx/printaccessoryview.mm | 1268 ++ vcl/osx/printview.mm | 80 + vcl/osx/res/MainMenu.nib/classes.nib | 4 + vcl/osx/res/MainMenu.nib/info.nib | 21 + vcl/osx/res/MainMenu.nib/keyedobjects.nib | Bin 0 -> 3615 bytes vcl/osx/saldata.cxx | 298 + vcl/osx/salframe.cxx | 1828 +++ vcl/osx/salframeview.mm | 1788 ++ vcl/osx/salinst.cxx | 987 ++ vcl/osx/salmenu.cxx | 902 + vcl/osx/salnativewidgets.cxx | 1141 ++ vcl/osx/salnsmenu.mm | 257 + vcl/osx/salnstimer.mm | 40 + vcl/osx/salobj.cxx | 442 + vcl/osx/salprn.cxx | 683 + vcl/osx/salsys.cxx | 117 + vcl/osx/saltimer.cxx | 209 + vcl/osx/service_entry.cxx | 64 + vcl/osx/vclnsapp.mm | 473 + vcl/qa/afl-eventtesting/README.eventtesting | 24 + vcl/qa/afl-eventtesting/eventtesting.impress | Bin 0 -> 196 bytes .../afl-eventtesting/eventtesting.impress.crash-1 | Bin 0 -> 235 bytes .../afl-eventtesting/eventtesting.impress.crash-2 | Bin 0 -> 110 bytes .../afl-eventtesting/eventtesting.impress.crash-3 | Bin 0 -> 196 bytes .../afl-eventtesting/eventtesting.impress.crash-4 | Bin 0 -> 208 bytes .../afl-eventtesting/eventtesting.impress.crash-5 | Bin 0 -> 184 bytes vcl/qa/afl-eventtesting/eventtesting.writer | Bin 0 -> 28 bytes vcl/qa/api/XGraphicTest.cxx | 241 + vcl/qa/api/data/TestGraphic.png | Bin 0 -> 81 bytes vcl/qa/cppunit/BackendTest.cxx | 599 + vcl/qa/cppunit/BitmapExTest.cxx | 113 + vcl/qa/cppunit/BitmapFilterTest.cxx | 216 + vcl/qa/cppunit/BitmapProcessorTest.cxx | 90 + vcl/qa/cppunit/BitmapScaleTest.cxx | 293 + vcl/qa/cppunit/BitmapTest.cxx | 660 + vcl/qa/cppunit/FontFeatureTest.cxx | 336 + vcl/qa/cppunit/GraphicDescriptorTest.cxx | 103 + vcl/qa/cppunit/GraphicFormatDetectorTest.cxx | 416 + vcl/qa/cppunit/GraphicNativeMetadataTest.cxx | 101 + vcl/qa/cppunit/GraphicTest.cxx | 435 + vcl/qa/cppunit/ScanlineToolsTest.cxx | 224 + vcl/qa/cppunit/TypeSerializerTest.cxx | 502 + vcl/qa/cppunit/app/test_IconThemeInfo.cxx | 116 + vcl/qa/cppunit/app/test_IconThemeScanner.cxx | 82 + vcl/qa/cppunit/app/test_IconThemeSelector.cxx | 183 + vcl/qa/cppunit/bitmapcolor.cxx | 262 + vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx | 269 + vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png | Bin 0 -> 106 bytes vcl/qa/cppunit/bitmaprender/data/tdf104141.gif | Bin 0 -> 12205 bytes vcl/qa/cppunit/bitmaprender/data/tdf113918.png | Bin 0 -> 20043 bytes vcl/qa/cppunit/bitmaprender/data/tdf116888.gif | Bin 0 -> 1875 bytes vcl/qa/cppunit/blocklistparsertest.cxx | 153 + vcl/qa/cppunit/builder/demo.ui | 1960 +++ vcl/qa/cppunit/canvasbitmaptest.cxx | 773 + vcl/qa/cppunit/complextext.cxx | 170 + vcl/qa/cppunit/data/123_Numbers.gif | Bin 0 -> 1515 bytes vcl/qa/cppunit/data/Exif1.jpg | Bin 0 -> 759 bytes vcl/qa/cppunit/data/Exif1_090CW.jpg | Bin 0 -> 771 bytes vcl/qa/cppunit/data/Exif1_180.jpg | Bin 0 -> 771 bytes vcl/qa/cppunit/data/Exif1_270CW.jpg | Bin 0 -> 771 bytes vcl/qa/cppunit/data/SimpleExample.svg | 4 + vcl/qa/cppunit/data/TypeDetectionExample.bmp | Bin 0 -> 442 bytes vcl/qa/cppunit/data/TypeDetectionExample.eps | 82 + vcl/qa/cppunit/data/TypeDetectionExample.gif | Bin 0 -> 50 bytes vcl/qa/cppunit/data/TypeDetectionExample.jpg | Bin 0 -> 992 bytes vcl/qa/cppunit/data/TypeDetectionExample.met | Bin 0 -> 629 bytes vcl/qa/cppunit/data/TypeDetectionExample.pcx | Bin 0 -> 284 bytes vcl/qa/cppunit/data/TypeDetectionExample.pdf | Bin 0 -> 962 bytes vcl/qa/cppunit/data/TypeDetectionExample.png | Bin 0 -> 94 bytes vcl/qa/cppunit/data/TypeDetectionExample.psd | Bin 0 -> 1338 bytes vcl/qa/cppunit/data/TypeDetectionExample.svg | 4 + vcl/qa/cppunit/data/TypeDetectionExample.svgz | Bin 0 -> 166 bytes vcl/qa/cppunit/data/TypeDetectionExample.tga | Bin 0 -> 148 bytes vcl/qa/cppunit/data/TypeDetectionExample.tif | Bin 0 -> 603 bytes vcl/qa/cppunit/data/TypeDetectionExample.wmf | Bin 0 -> 290 bytes vcl/qa/cppunit/data/TypeDetectionExample.xbm | 5 + vcl/qa/cppunit/data/TypeDetectionExample.xpm | 15 + vcl/qa/cppunit/data/inch-size.emf | Bin 0 -> 28322 bytes vcl/qa/cppunit/data/testBasicMorphology.png | Bin 0 -> 226 bytes .../cppunit/data/testBasicMorphologyDilated1.png | Bin 0 -> 219 bytes .../data/testBasicMorphologyDilated1Eroded1.png | Bin 0 -> 224 bytes .../cppunit/data/testBasicMorphologyDilated2.png | Bin 0 -> 174 bytes .../data/testBasicMorphologyDilated2Eroded1.png | Bin 0 -> 178 bytes vcl/qa/cppunit/dndtest.cxx | 311 + vcl/qa/cppunit/errorhandler.cxx | 73 + .../cppunit/filter/ipdf/data/dict-array-dict.pdf | 55 + vcl/qa/cppunit/filter/ipdf/ipdf.cxx | 73 + vcl/qa/cppunit/font.cxx | 161 + vcl/qa/cppunit/fontcharmap.cxx | 45 + vcl/qa/cppunit/fontmetric.cxx | 138 + vcl/qa/cppunit/gen/data/tdf121120.png | Bin 0 -> 3196 bytes vcl/qa/cppunit/gen/gen.cxx | 116 + vcl/qa/cppunit/graphicfilter/data/README | 7 + .../cppunit/graphicfilter/data/bmp/fail/.gitignore | 0 .../data/bmp/fail/CVE-2004-0691-1.bmp | Bin 0 -> 313 bytes .../data/bmp/fail/CVE-2006-0006-1.bmp | Bin 0 -> 43218 bytes .../data/bmp/fail/CVE-2007-2244-1.bmp | Bin 0 -> 21424 bytes .../data/bmp/fail/CVE-2007-3741-1.bmp | Bin 0 -> 8585 bytes .../data/bmp/fail/CVE-2007-3741-2.bmp | Bin 0 -> 8620 bytes .../data/bmp/fail/CVE-2008-1097-1.bmp | Bin 0 -> 93078 bytes .../data/bmp/fail/CVE-2008-5870-1.bmp | 1 + .../data/bmp/fail/CVE-2016-10504-1.bmp | Bin 0 -> 2616 bytes .../graphicfilter/data/bmp/fail/EDB-24743-1.bmp | Bin 0 -> 2222 bytes .../graphicfilter/data/bmp/fail/EDB-24743-4.bmp | Bin 0 -> 73470 bytes .../data/bmp/fail/afl-sample-bad-rle-1.bmp | Bin 0 -> 1038 bytes .../graphicfilter/data/bmp/fail/crash-1.bmp | Bin 0 -> 632 bytes .../data/bmp/fail/nodict-compress.bmp | Bin 0 -> 110 bytes .../data/bmp/indeterminate/.gitignore | 1 + .../cppunit/graphicfilter/data/bmp/pass/.gitignore | 0 .../data/bmp/pass/CVE-2014-1947-1.bmp | Bin 0 -> 5000 bytes .../graphicfilter/data/bmp/pass/EDB-22680-1.bmp | Bin 0 -> 18862 bytes .../cppunit/graphicfilter/data/emf/fail/.gitignore | 0 .../data/emf/fail/CVE-2004-0209-1.emf | Bin 0 -> 576 bytes .../data/emf/fail/CVE-2008-1083-1.emf | Bin 0 -> 3524 bytes .../data/emf/fail/CVE-2009-1217-1.emf | Bin 0 -> 1075 bytes .../graphicfilter/data/emf/fail/crash-2.emf | Bin 0 -> 3848 bytes .../graphicfilter/data/emf/fail/crash-3.emf | Bin 0 -> 456 bytes .../graphicfilter/data/emf/fail/fdo71307-2.emf | Bin 0 -> 24229 bytes .../cppunit/graphicfilter/data/emf/fail/hang-1.emf | Bin 0 -> 2225 bytes .../cppunit/graphicfilter/data/emf/fail/hang-2.emf | Bin 0 -> 7057 bytes .../data/emf/fail/slow-moveclip-1.emf | Bin 0 -> 8700 bytes .../data/emf/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/emf/pass/.gitignore | 0 .../data/emf/pass/CVE-2008-1087-1.emf | Bin 0 -> 3380 bytes .../data/emf/pass/CVE-2008-2245-1.emf | Bin 0 -> 3524 bytes .../data/emf/pass/CVE-2016-0168-1.emf | Bin 0 -> 1040240 bytes .../data/emf/pass/CVE-2016-0168-2.emf | Bin 0 -> 3872 bytes .../data/emf/pass/CVE-2016-0169-1.emf | Bin 0 -> 3792 bytes .../data/emf/pass/CVE-2016-0169-2.emf | Bin 0 -> 3792 bytes .../data/emf/pass/CVE-2016-0169-3.emf | Bin 0 -> 3792 bytes .../data/emf/pass/CVE-2016-0170-1.emf | Bin 0 -> 3792 bytes .../data/emf/pass/CVE-2016-3301-1.emf | Bin 0 -> 42756 bytes .../data/emf/pass/CVE-2016-3303-1.emf | Bin 0 -> 42756 bytes .../data/emf/pass/CVE-2016-3304-1.emf | Bin 0 -> 25160 bytes .../graphicfilter/data/emf/pass/crash-1.emf | Bin 0 -> 7068 bytes .../graphicfilter/data/emf/pass/crash-2.emf | Bin 0 -> 133136 bytes .../graphicfilter/data/emf/pass/fdo38580-3.emf | Bin 0 -> 7068 bytes .../cppunit/graphicfilter/data/gif/fail/.gitignore | 0 .../data/gif/fail/CVE-2007-3958-1.gif | Bin 0 -> 328 bytes .../data/gif/fail/CVE-2008-5937-1.gif | 1 + .../graphicfilter/data/gif/fail/EBD-36334-1.gif | 2 + .../graphicfilter/data/gif/fail/EBD-36335-1.gif | Bin 0 -> 1190 bytes .../graphicfilter/data/gif/fail/EDB-23279-1.gif | 1 + .../graphicfilter/data/gif/fail/too-small-1.gif | Bin 0 -> 3080 bytes .../data/gif/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/gif/pass/.gitignore | 0 .../data/gif/pass/CVE-2007-6715-1.gif | Bin 0 -> 47778 bytes .../data/gif/pass/CVE-2008-3013-1.gif | Bin 0 -> 2382 bytes .../data/gif/pass/CVE-2011-2131-1.gif | Bin 0 -> 10998 bytes .../data/gif/pass/CVE-2012-0282-1.gif | Bin 0 -> 2876 bytes .../graphicfilter/data/gif/pass/EDB-19333-1.gif | 1 + .../data/gif/pass/afl-sample-short-read-1.gif | Bin 0 -> 275 bytes .../data/gif/pass/afl-sample-short-read-2.gif | Bin 0 -> 35 bytes .../graphicfilter/data/gif/pass/crash-1.gif | Bin 0 -> 111 bytes .../graphicfilter/data/gif/pass/crash-2.gif | Bin 0 -> 257 bytes ...8c9b19bb548826bed0599f65745-15940-minimized.gif | Bin 0 -> 47778 bytes .../cppunit/graphicfilter/data/jpg/fail/.gitignore | 0 .../data/jpg/fail/CVE-2008-1097-1.jpg | Bin 0 -> 31214 bytes .../data/jpg/fail/CVE-2008-1097-2.jpg | Bin 0 -> 31129 bytes .../data/jpg/fail/CVE-2008-1097-3.jpg | Bin 0 -> 31214 bytes .../data/jpg/fail/CVE-2008-1097-4.jpg | Bin 0 -> 31214 bytes .../data/jpg/fail/CVE-2008-1097-5.jpg | Bin 0 -> 31214 bytes .../data/jpg/fail/CVE-2008-5314-1.jpg | Bin 0 -> 12000000 bytes .../graphicfilter/data/jpg/fail/crash-1.jpg | Bin 0 -> 443 bytes .../data/jpg/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/jpg/pass/.gitignore | 0 .../data/jpg/pass/CVE-2004-0200-1.jpg | Bin 0 -> 4098 bytes .../data/jpg/pass/CVE-2004-0200-2.jpg | Bin 0 -> 1674 bytes .../data/jpg/pass/CVE-2004-0200-3.jpg | Bin 0 -> 2634 bytes .../data/jpg/pass/CVE-2004-0200-4.jpg | Bin 0 -> 4098 bytes .../data/jpg/pass/CVE-2004-0200-5.jpg | Bin 0 -> 8903 bytes .../data/jpg/pass/CVE-2017-9614-1.jpg | Bin 0 -> 504 bytes .../graphicfilter/data/jpg/pass/EDB-24743-2.jpg | Bin 0 -> 8559 bytes .../graphicfilter/data/jpg/pass/EDB-24743-3.jpg | Bin 0 -> 24253 bytes .../graphicfilter/data/jpg/pass/fatalerror-1.jpg | Bin 0 -> 276 bytes .../cppunit/graphicfilter/data/png/fail/.gitignore | 0 .../data/png/fail/CVE-2004-0597-1.png | 3 + .../data/png/fail/CVE-2005-0633-1.png | Bin 0 -> 346 bytes .../data/png/fail/CVE-2006-7210-1.png | Bin 0 -> 2495 bytes .../data/png/fail/CVE-2007-2365-1.png | Bin 0 -> 18470 bytes .../data/png/fail/CVE-2009-1511-1.png | 1 + .../data/png/fail/CVE-2016-0951-2.png | 1 + .../data/png/fail/CVE-2016-0952-2.png | Bin 0 -> 383 bytes .../graphicfilter/data/png/fail/EDB-34720-1.png | Bin 0 -> 5000 bytes .../data/png/fail/afl-sample-Z_NEED_DICT.png | Bin 0 -> 260 bytes .../data/png/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/png/pass/.gitignore | 0 .../data/png/pass/CVE-2016-0951-1.png | 1 + .../data/png/pass/CVE-2016-0952-1.png | 1 + .../data/png/pass/afl-sample-IDAT.png | Bin 0 -> 260 bytes .../cppunit/graphicfilter/data/png/pass/black.png | Bin 0 -> 175 bytes .../graphicfilter/data/png/pass/invalid-chunk.png | Bin 0 -> 5312 bytes .../cppunit/graphicfilter/data/svm/fail/.gitignore | 0 .../graphicfilter/data/svm/fail/mapmode-1.svm | Bin 0 -> 152 bytes .../graphicfilter/data/svm/fail/mapmode-2.svm | Bin 0 -> 110 bytes .../graphicfilter/data/svm/fail/mapmode-3.svm | Bin 0 -> 142 bytes .../graphicfilter/data/svm/fail/mapmode-4.svm | Bin 0 -> 532 bytes .../graphicfilter/data/svm/fail/mapmode-5.svm | Bin 0 -> 162 bytes .../graphicfilter/data/svm/fail/mapmode-6.svm | Bin 0 -> 79 bytes .../graphicfilter/data/svm/fail/ofz7165-1.svm | Bin 0 -> 816777 bytes .../data/svm/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/svm/pass/.gitignore | 0 .../cppunit/graphicfilter/data/svm/pass/leak-1.svm | Bin 0 -> 856 bytes .../cppunit/graphicfilter/data/wmf/fail/.gitignore | 0 .../data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 | Bin 0 -> 684 bytes .../data/wmf/fail/CVE-2005-2124-1.wmf | Bin 0 -> 218 bytes .../data/wmf/fail/CVE-2005-4560-1.wmf | Bin 0 -> 12178 bytes .../data/wmf/fail/CVE-2006-0143-1.wmf | 1 + .../data/wmf/fail/CVE-2006-0143-2.wmf | Bin 0 -> 68 bytes .../data/wmf/fail/CVE-2007-1238-1.wmf | Bin 0 -> 382 bytes .../data/wmf/fail/CVE-2007-1245-1.wmf | Bin 0 -> 382 bytes .../graphicfilter/data/wmf/fail/RC4-hang-1.wmf | Bin 0 -> 675 bytes .../graphicfilter/data/wmf/fail/RC4-hang-2.wmf | Bin 0 -> 375 bytes .../graphicfilter/data/wmf/fail/RC4-hang-3.wmf | 5 + .../graphicfilter/data/wmf/fail/RC4-hang-4.wmf | 3 + .../graphicfilter/data/wmf/fail/bitcount-1.wmf | Bin 0 -> 1916 bytes .../graphicfilter/data/wmf/fail/exttextout-2.wmf | Bin 0 -> 54196 bytes .../graphicfilter/data/wmf/fail/facename-1.wmf | Bin 0 -> 4197 bytes .../graphicfilter/data/wmf/fail/ofz5942-1.wmf | Bin 0 -> 16064 bytes .../cppunit/graphicfilter/data/wmf/fail/seek-1.wmf | Bin 0 -> 5082 bytes .../data/wmf/indeterminate/.gitignore | 1 + .../cppunit/graphicfilter/data/wmf/pass/.gitignore | 0 .../data/wmf/pass/CVE-2005-2123-1.wmf | Bin 0 -> 684 bytes .../data/wmf/pass/CVE-2006-4071-1.wmf | 1 + .../data/wmf/pass/CVE-2007-1090-1.wmf | Bin 0 -> 238 bytes .../data/wmf/pass/CVE-2015-0848-1.wmf | Bin 0 -> 4192 bytes .../graphicfilter/data/wmf/pass/exttextout-1.wmf | Bin 0 -> 2142 bytes .../graphicfilter/data/wmf/pass/noheader.wmf | Bin 0 -> 13801 bytes .../cppunit/graphicfilter/data/xbm/fail/.gitignore | 0 .../graphicfilter/data/xbm/fail/crash-1.xbm | 12 + .../data/xbm/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/xbm/pass/.gitignore | 0 .../graphicfilter/data/xbm/pass/grafix4.xbm | 2011 +++ .../cppunit/graphicfilter/data/xpm/fail/.gitignore | 0 .../graphicfilter/data/xpm/fail/gentoo22729-1.xpm | Bin 0 -> 645514 bytes .../data/xpm/indeterminate/.gitignore | 0 .../cppunit/graphicfilter/data/xpm/pass/.gitignore | 0 .../graphicfilter/data/xpm/pass/tdf111925-1.xpm | 306 + vcl/qa/cppunit/graphicfilter/filters-test.cxx | 181 + vcl/qa/cppunit/jpeg/JpegReaderTest.cxx | 167 + vcl/qa/cppunit/jpeg/JpegWriterTest.cxx | 105 + vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg | Bin 0 -> 1384 bytes vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif | Bin 0 -> 1875 bytes vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg | Bin 0 -> 405 bytes vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg | Bin 0 -> 196 bytes vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg | Bin 0 -> 619 bytes vcl/qa/cppunit/lifecycle.cxx | 357 + vcl/qa/cppunit/mnemonic.cxx | 57 + vcl/qa/cppunit/outdev.cxx | 291 + vcl/qa/cppunit/pdfexport/data/6m-wide.odg | Bin 0 -> 9146 bytes .../cppunit/pdfexport/data/SimpleMultiPagePDF.pdf | Bin 0 -> 17693 bytes vcl/qa/cppunit/pdfexport/data/forcepoint71.key | Bin 0 -> 114022 bytes vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp | Bin 0 -> 12293 bytes .../data/pdf-image-resource-inline-xobject-ref.pdf | Bin 0 -> 1372 bytes vcl/qa/cppunit/pdfexport/data/reduce-image.fodt | 29 + .../cppunit/pdfexport/data/reduce-small-image.fodt | 21 + vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt | Bin 0 -> 9071 bytes vcl/qa/cppunit/pdfexport/data/tdf105093.odp | Bin 0 -> 211126 bytes vcl/qa/cppunit/pdfexport/data/tdf105461.odp | Bin 0 -> 10320 bytes vcl/qa/cppunit/pdfexport/data/tdf105954.odt | Bin 0 -> 74147 bytes vcl/qa/cppunit/pdfexport/data/tdf106059.odt | Bin 0 -> 13585 bytes vcl/qa/cppunit/pdfexport/data/tdf106206.odt | Bin 0 -> 74641 bytes vcl/qa/cppunit/pdfexport/data/tdf106693.odt | Bin 0 -> 13585 bytes vcl/qa/cppunit/pdfexport/data/tdf106702.odt | Bin 0 -> 42158 bytes vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt | Bin 0 -> 21561 bytes vcl/qa/cppunit/pdfexport/data/tdf106972.odt | Bin 0 -> 21376 bytes vcl/qa/cppunit/pdfexport/data/tdf107013.odt | Bin 0 -> 19823 bytes vcl/qa/cppunit/pdfexport/data/tdf107018.odt | Bin 0 -> 15787 bytes vcl/qa/cppunit/pdfexport/data/tdf107089.odt | Bin 0 -> 20171 bytes vcl/qa/cppunit/pdfexport/data/tdf107868.odt | Bin 0 -> 10567 bytes vcl/qa/cppunit/pdfexport/data/tdf108963.odp | Bin 0 -> 10369 bytes vcl/qa/cppunit/pdfexport/data/tdf109143.odt | Bin 0 -> 68155 bytes vcl/qa/cppunit/pdfexport/data/tdf113143.odp | Bin 0 -> 100637 bytes vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt | Bin 0 -> 8566 bytes vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt | Bin 0 -> 8629 bytes vcl/qa/cppunit/pdfexport/data/tdf115262.ods | Bin 0 -> 27638 bytes vcl/qa/cppunit/pdfexport/data/tdf115967.odt | Bin 0 -> 12091 bytes .../pdfexport/data/tdf118244_radioButtonGroup.odt | Bin 0 -> 12847 bytes vcl/qa/cppunit/pdfexport/data/tdf121615.odt | Bin 0 -> 10188 bytes vcl/qa/cppunit/pdfexport/data/tdf121962.odt | Bin 0 -> 14974 bytes vcl/qa/cppunit/pdfexport/data/tdf128630.odp | Bin 0 -> 17558 bytes vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt | Bin 0 -> 8154 bytes vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt | Bin 0 -> 8265 bytes vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt | Bin 0 -> 8251 bytes vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt | Bin 0 -> 215797 bytes vcl/qa/cppunit/pdfexport/data/tdf99680.odt | Bin 0 -> 30257 bytes vcl/qa/cppunit/pdfexport/data/toc-link.fodt | 45 + vcl/qa/cppunit/pdfexport/pdfexport.cxx | 2295 +++ vcl/qa/cppunit/png/PngFilterTest.cxx | 193 + vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png | Bin 0 -> 158 bytes vcl/qa/cppunit/png/data/color-rect-4bit-pal.png | Bin 0 -> 104 bytes vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png | Bin 0 -> 90 bytes vcl/qa/cppunit/png/data/rect-1bit-pal.png | Bin 0 -> 89 bytes vcl/qa/cppunit/svm/data/arc.svm | Bin 0 -> 279 bytes vcl/qa/cppunit/svm/data/bitmapexs.svm | Bin 0 -> 3773 bytes vcl/qa/cppunit/svm/data/bitmaps.svm | Bin 0 -> 599 bytes vcl/qa/cppunit/svm/data/chord.svm | Bin 0 -> 279 bytes vcl/qa/cppunit/svm/data/clipregion.svm | Bin 0 -> 255 bytes vcl/qa/cppunit/svm/data/ellipse.svm | Bin 0 -> 263 bytes vcl/qa/cppunit/svm/data/fillcolor.svm | Bin 0 -> 244 bytes vcl/qa/cppunit/svm/data/gradient.svm | Bin 0 -> 15497 bytes vcl/qa/cppunit/svm/data/hatch.svm | Bin 0 -> 271 bytes vcl/qa/cppunit/svm/data/line.svm | Bin 0 -> 325 bytes vcl/qa/cppunit/svm/data/linecolor.svm | Bin 0 -> 244 bytes vcl/qa/cppunit/svm/data/masks.svm | Bin 0 -> 603 bytes vcl/qa/cppunit/svm/data/overlinecolor.svm | Bin 0 -> 244 bytes vcl/qa/cppunit/svm/data/pie.svm | Bin 0 -> 279 bytes vcl/qa/cppunit/svm/data/pixel.svm | Bin 0 -> 253 bytes vcl/qa/cppunit/svm/data/point.svm | Bin 0 -> 229 bytes vcl/qa/cppunit/svm/data/polygon.svm | Bin 0 -> 336 bytes vcl/qa/cppunit/svm/data/polyline.svm | Bin 0 -> 400 bytes vcl/qa/cppunit/svm/data/polypolygon.svm | Bin 0 -> 332 bytes vcl/qa/cppunit/svm/data/pushpop.svm | Bin 0 -> 456 bytes vcl/qa/cppunit/svm/data/rasterop.svm | Bin 0 -> 223 bytes vcl/qa/cppunit/svm/data/rect.svm | Bin 0 -> 263 bytes vcl/qa/cppunit/svm/data/roundrect.svm | Bin 0 -> 271 bytes vcl/qa/cppunit/svm/data/strecthtext.svm | Bin 0 -> 259 bytes vcl/qa/cppunit/svm/data/text.svm | Bin 0 -> 249 bytes vcl/qa/cppunit/svm/data/textalign.svm | Bin 0 -> 223 bytes vcl/qa/cppunit/svm/data/textarray.svm | Bin 0 -> 275 bytes vcl/qa/cppunit/svm/data/textcolor.svm | Bin 0 -> 225 bytes vcl/qa/cppunit/svm/data/textfillecolor.svm | Bin 0 -> 226 bytes vcl/qa/cppunit/svm/data/textline.svm | Bin 0 -> 245 bytes vcl/qa/cppunit/svm/data/textlinecolor.svm | Bin 0 -> 226 bytes vcl/qa/cppunit/svm/data/textrectangle.svm | Bin 0 -> 261 bytes vcl/qa/cppunit/svm/data/transparent.svm | Bin 0 -> 251 bytes vcl/qa/cppunit/svm/data/wallpaper.svm | Bin 0 -> 323 bytes vcl/qa/cppunit/svm/svmtest.cxx | 1684 ++ vcl/qa/cppunit/test_blocklist_evaluate.xml | 46 + vcl/qa/cppunit/test_blocklist_parse.xml | 63 + vcl/qa/cppunit/timer.cxx | 566 + .../widgetdraw/WidgetDefinitionReaderTest.cxx | 132 + vcl/qa/cppunit/widgetdraw/data/definition1.xml | 82 + .../widgetdraw/data/definitionSettings1.xml | 5 + .../widgetdraw/data/definitionSettings2.xml | 6 + .../widgetdraw/data/definitionSettings3.xml | 13 + vcl/qa/unit/data/vcl-dialogs-test.txt | 45 + vcl/qa/unit/vcl-dialogs-test.cxx | 63 + vcl/qt5/Qt5AccessibleEventListener.cxx | 174 + vcl/qt5/Qt5AccessibleWidget.cxx | 1267 ++ vcl/qt5/Qt5Bitmap.cxx | 301 + vcl/qt5/Qt5Clipboard.cxx | 243 + vcl/qt5/Qt5Data.cxx | 334 + vcl/qt5/Qt5DragAndDrop.cxx | 252 + vcl/qt5/Qt5FilePicker.cxx | 945 ++ vcl/qt5/Qt5Font.cxx | 161 + vcl/qt5/Qt5FontFace.cxx | 206 + vcl/qt5/Qt5Frame.cxx | 1449 ++ vcl/qt5/Qt5Graphics.cxx | 128 + vcl/qt5/Qt5Graphics_Controls.cxx | 1111 ++ vcl/qt5/Qt5Graphics_GDI.cxx | 712 + vcl/qt5/Qt5Graphics_Text.cxx | 233 + vcl/qt5/Qt5Instance.cxx | 651 + vcl/qt5/Qt5Instance_Print.cxx | 132 + vcl/qt5/Qt5MainWindow.cxx | 45 + vcl/qt5/Qt5Menu.cxx | 704 + vcl/qt5/Qt5Object.cxx | 156 + vcl/qt5/Qt5OpenGLContext.cxx | 152 + vcl/qt5/Qt5Painter.cxx | 53 + vcl/qt5/Qt5Printer.cxx | 27 + vcl/qt5/Qt5SvpGraphics.cxx | 114 + vcl/qt5/Qt5SvpSurface.cxx | 91 + vcl/qt5/Qt5SvpVirtualDevice.hxx | 37 + vcl/qt5/Qt5System.cxx | 38 + vcl/qt5/Qt5Timer.cxx | 52 + vcl/qt5/Qt5Tools.cxx | 122 + vcl/qt5/Qt5Transferable.cxx | 345 + vcl/qt5/Qt5VirtualDevice.cxx | 93 + vcl/qt5/Qt5Widget.cxx | 740 + vcl/qt5/Qt5XAccessible.cxx | 29 + vcl/quartz/ctfonts.cxx | 560 + vcl/quartz/salbmp.cxx | 963 ++ vcl/quartz/salgdi.cxx | 888 + vcl/quartz/salgdicommon.cxx | 2047 +++ vcl/quartz/salgdiutils.cxx | 265 + vcl/quartz/salvd.cxx | 303 + vcl/quartz/utils.cxx | 161 + vcl/skia/README | 35 + vcl/skia/SkiaHelper.cxx | 611 + vcl/skia/gdiimpl.cxx | 1829 +++ vcl/skia/salbmp.cxx | 819 + vcl/skia/skia_blacklist_vulkan.xml | 37 + vcl/skia/win/gdiimpl.cxx | 393 + vcl/skia/x11/gdiimpl.cxx | 161 + vcl/skia/x11/salvd.cxx | 86 + vcl/skia/x11/textrender.cxx | 80 + vcl/skia/zone.cxx | 76 + vcl/source/animate/Animation.cxx | 678 + vcl/source/animate/AnimationBitmap.cxx | 53 + vcl/source/app/ITiledRenderable.cxx | 81 + vcl/source/app/IconThemeInfo.cxx | 188 + vcl/source/app/IconThemeScanner.cxx | 215 + vcl/source/app/IconThemeSelector.cxx | 175 + vcl/source/app/brand.cxx | 73 + vcl/source/app/customweld.cxx | 105 + vcl/source/app/dbggui.cxx | 50 + vcl/source/app/dndhelp.cxx | 139 + vcl/source/app/help.cxx | 677 + vcl/source/app/i18nhelp.cxx | 160 + vcl/source/app/idle.cxx | 65 + vcl/source/app/salplug.cxx | 355 + vcl/source/app/salusereventlist.cxx | 171 + vcl/source/app/salvtables.cxx | 6777 ++++++++ vcl/source/app/scheduler.cxx | 659 + vcl/source/app/session.cxx | 414 + vcl/source/app/settings.cxx | 3233 ++++ vcl/source/app/sound.cxx | 38 + vcl/source/app/stdtext.cxx | 124 + vcl/source/app/svapp.cxx | 1707 ++ vcl/source/app/svdata.cxx | 491 + vcl/source/app/svmain.cxx | 684 + vcl/source/app/timer.cxx | 102 + vcl/source/app/unohelp.cxx | 233 + vcl/source/app/unohelp2.cxx | 98 + vcl/source/app/vclevent.cxx | 104 + vcl/source/app/watchdog.cxx | 165 + vcl/source/app/weldutils.cxx | 129 + vcl/source/app/winscheduler.cxx | 46 + vcl/source/bitmap/BitmapAlphaClampFilter.cxx | 45 + vcl/source/bitmap/BitmapBasicMorphologyFilter.cxx | 360 + .../bitmap/BitmapColorQuantizationFilter.cxx | 232 + vcl/source/bitmap/BitmapColorizeFilter.cxx | 92 + .../bitmap/BitmapConvolutionMatrixFilter.cxx | 208 + vcl/source/bitmap/BitmapDisabledImageFilter.cxx | 61 + vcl/source/bitmap/BitmapDuoToneFilter.cxx | 65 + vcl/source/bitmap/BitmapEmbossGreyFilter.cxx | 158 + vcl/source/bitmap/BitmapFastScaleFilter.cxx | 131 + vcl/source/bitmap/BitmapFilterStackBlur.cxx | 629 + .../bitmap/BitmapGaussianSeparableBlurFilter.cxx | 215 + vcl/source/bitmap/BitmapInterpolateScaleFilter.cxx | 237 + vcl/source/bitmap/BitmapLightenFilter.cxx | 69 + vcl/source/bitmap/BitmapMedianFilter.cxx | 218 + vcl/source/bitmap/BitmapMonochromeFilter.cxx | 101 + vcl/source/bitmap/BitmapMosaicFilter.cxx | 185 + vcl/source/bitmap/BitmapPopArtFilter.cxx | 97 + vcl/source/bitmap/BitmapScaleConvolutionFilter.cxx | 391 + vcl/source/bitmap/BitmapScaleSuperFilter.cxx | 1202 ++ .../bitmap/BitmapSeparableUnsharpenFilter.cxx | 75 + vcl/source/bitmap/BitmapSepiaFilter.cxx | 111 + .../bitmap/BitmapSimpleColorQuantizationFilter.cxx | 113 + vcl/source/bitmap/BitmapSmoothenFilter.cxx | 32 + vcl/source/bitmap/BitmapSobelGreyFilter.cxx | 170 + vcl/source/bitmap/BitmapSolarizeFilter.cxx | 71 + vcl/source/bitmap/BitmapSymmetryCheck.cxx | 84 + vcl/source/bitmap/BitmapTools.cxx | 1131 ++ vcl/source/bitmap/Octree.cxx | 288 + vcl/source/bitmap/bitmap.cxx | 892 + vcl/source/bitmap/bitmapfilter.cxx | 58 + vcl/source/bitmap/bitmappaint.cxx | 1146 ++ vcl/source/bitmap/checksum.cxx | 154 + vcl/source/bitmap/salbmp.cxx | 225 + vcl/source/components/dtranscomp.cxx | 491 + vcl/source/components/factory.cxx | 85 + vcl/source/components/fontident.cxx | 184 + vcl/source/control/InterimItemWindow.cxx | 99 + vcl/source/control/button.cxx | 3705 +++++ vcl/source/control/calendar.cxx | 1554 ++ vcl/source/control/combobox.cxx | 1542 ++ vcl/source/control/ctrl.cxx | 495 + vcl/source/control/edit.cxx | 2939 ++++ vcl/source/control/field.cxx | 2059 +++ vcl/source/control/field2.cxx | 2708 +++ vcl/source/control/fixed.cxx | 972 ++ vcl/source/control/fixedhyper.cxx | 185 + vcl/source/control/fmtfield.cxx | 1291 ++ vcl/source/control/hyperlabel.cxx | 200 + vcl/source/control/imgctrl.cxx | 184 + vcl/source/control/imivctl.hxx | 513 + vcl/source/control/imivctl1.cxx | 2980 ++++ vcl/source/control/imivctl2.cxx | 715 + vcl/source/control/imp_listbox.cxx | 3116 ++++ vcl/source/control/ivctrl.cxx | 633 + vcl/source/control/listbox.cxx | 1444 ++ vcl/source/control/longcurr.cxx | 516 + vcl/source/control/menubtn.cxx | 250 + vcl/source/control/notebookbar.cxx | 297 + vcl/source/control/prgsbar.cxx | 229 + vcl/source/control/quickselectionengine.cxx | 161 + vcl/source/control/roadmap.cxx | 842 + vcl/source/control/roadmapwizard.cxx | 858 + vcl/source/control/scrbar.cxx | 1469 ++ vcl/source/control/slider.cxx | 906 ++ vcl/source/control/spinbtn.cxx | 468 + vcl/source/control/spinfld.cxx | 1007 ++ vcl/source/control/tabctrl.cxx | 2382 +++ vcl/source/control/throbber.cxx | 232 + vcl/source/control/thumbpos.hxx | 23 + vcl/source/control/wizardmachine.cxx | 1496 ++ vcl/source/control/wizimpldata.hxx | 64 + vcl/source/edit/textdat2.hxx | 283 + vcl/source/edit/textdata.cxx | 343 + vcl/source/edit/textdoc.cxx | 536 + vcl/source/edit/textdoc.hxx | 129 + vcl/source/edit/texteng.cxx | 2896 ++++ vcl/source/edit/textund2.hxx | 108 + vcl/source/edit/textundo.cxx | 330 + vcl/source/edit/textundo.hxx | 80 + vcl/source/edit/textview.cxx | 2302 +++ vcl/source/edit/txtattr.cxx | 93 + vcl/source/edit/vclmedit.cxx | 1539 ++ vcl/source/edit/xtextedt.cxx | 227 + vcl/source/filter/FilterConfigCache.cxx | 539 + vcl/source/filter/FilterConfigCache.hxx | 108 + vcl/source/filter/FilterConfigItem.cxx | 393 + vcl/source/filter/GraphicFormatDetector.cxx | 550 + vcl/source/filter/GraphicNativeMetadata.cxx | 61 + vcl/source/filter/GraphicNativeTransform.cxx | 169 + vcl/source/filter/graphicfilter.cxx | 2303 +++ vcl/source/filter/graphicfilter2.cxx | 1165 ++ vcl/source/filter/graphicfilter_internal.hxx | 32 + vcl/source/filter/igif/decode.cxx | 215 + vcl/source/filter/igif/decode.hxx | 66 + vcl/source/filter/igif/gifread.cxx | 994 ++ vcl/source/filter/igif/gifread.hxx | 30 + vcl/source/filter/ipdf/pdfdocument.cxx | 3100 ++++ vcl/source/filter/ipdf/pdfread.cxx | 311 + vcl/source/filter/ixbm/xbmread.cxx | 395 + vcl/source/filter/ixbm/xbmread.hxx | 29 + vcl/source/filter/ixpm/rgbtable.hxx | 696 + vcl/source/filter/ixpm/xpmread.cxx | 695 + vcl/source/filter/ixpm/xpmread.hxx | 31 + vcl/source/filter/jpeg/Exif.cxx | 295 + vcl/source/filter/jpeg/Exif.hxx | 83 + vcl/source/filter/jpeg/JpegReader.cxx | 331 + vcl/source/filter/jpeg/JpegReader.hxx | 73 + vcl/source/filter/jpeg/JpegTransform.cxx | 45 + vcl/source/filter/jpeg/JpegTransform.hxx | 42 + vcl/source/filter/jpeg/JpegWriter.cxx | 265 + vcl/source/filter/jpeg/JpegWriter.hxx | 56 + vcl/source/filter/jpeg/jinclude.h | 81 + vcl/source/filter/jpeg/jpeg.cxx | 62 + vcl/source/filter/jpeg/jpeg.h | 67 + vcl/source/filter/jpeg/jpeg.hxx | 37 + vcl/source/filter/jpeg/jpegc.cxx | 513 + vcl/source/filter/jpeg/jpegcomp.h | 18 + vcl/source/filter/jpeg/transupp.c | 1570 ++ vcl/source/filter/jpeg/transupp.h | 212 + vcl/source/filter/png/PngImageReader.cxx | 279 + vcl/source/filter/png/pngread.cxx | 1715 ++ vcl/source/filter/png/pngwrite.cxx | 720 + vcl/source/filter/wmf/emfwr.cxx | 1483 ++ vcl/source/filter/wmf/emfwr.hxx | 114 + vcl/source/filter/wmf/wmf.cxx | 107 + vcl/source/filter/wmf/wmfexternal.cxx | 77 + vcl/source/filter/wmf/wmfwr.cxx | 1895 +++ vcl/source/filter/wmf/wmfwr.hxx | 205 + vcl/source/font/Feature.cxx | 165 + vcl/source/font/FeatureCollector.cxx | 158 + vcl/source/font/FeatureParser.cxx | 69 + vcl/source/font/OpenTypeFeatureDefinitionList.cxx | 197 + vcl/source/font/PhysicalFontCollection.cxx | 1267 ++ vcl/source/font/PhysicalFontFace.cxx | 199 + vcl/source/font/PhysicalFontFamily.cxx | 273 + vcl/source/font/font.cxx | 894 + vcl/source/font/fontattributes.cxx | 62 + vcl/source/font/fontcache.cxx | 278 + vcl/source/font/fontcharmap.cxx | 634 + vcl/source/font/fontinstance.cxx | 168 + vcl/source/font/fontmetric.cxx | 394 + vcl/source/font/fontselect.cxx | 150 + vcl/source/fontsubset/cff.cxx | 2061 +++ vcl/source/fontsubset/fontsubset.cxx | 163 + vcl/source/fontsubset/list.cxx | 229 + vcl/source/fontsubset/list.h | 89 + vcl/source/fontsubset/sft.cxx | 2635 +++ vcl/source/fontsubset/ttcr.cxx | 1505 ++ vcl/source/fontsubset/ttcr.hxx | 220 + vcl/source/fontsubset/xlat.cxx | 144 + vcl/source/fontsubset/xlat.hxx | 40 + vcl/source/gdi/CommonSalLayout.cxx | 854 + vcl/source/gdi/FileDefinitionWidgetDraw.cxx | 1080 ++ vcl/source/gdi/TypeSerializer.cxx | 419 + vcl/source/gdi/VerticalOrientationData.cxx | 78 + vcl/source/gdi/WidgetDefinition.cxx | 186 + vcl/source/gdi/WidgetDefinitionReader.cxx | 494 + vcl/source/gdi/alpha.cxx | 176 + vcl/source/gdi/bitmap3.cxx | 1146 ++ vcl/source/gdi/bitmapex.cxx | 1685 ++ vcl/source/gdi/bmpacc.cxx | 464 + vcl/source/gdi/bmpacc2.cxx | 362 + vcl/source/gdi/bmpacc3.cxx | 278 + vcl/source/gdi/bmpfast.cxx | 743 + vcl/source/gdi/configsettings.cxx | 137 + vcl/source/gdi/cvtgrf.cxx | 73 + vcl/source/gdi/dibtools.cxx | 1904 +++ vcl/source/gdi/embeddedfontshelper.cxx | 332 + vcl/source/gdi/extoutdevdata.cxx | 31 + vcl/source/gdi/gdimetafiletools.cxx | 1086 ++ vcl/source/gdi/gdimtf.cxx | 2866 ++++ vcl/source/gdi/genVerticalOrientationData.pl | 206 + vcl/source/gdi/gfxlink.cxx | 189 + vcl/source/gdi/gradient.cxx | 285 + vcl/source/gdi/graph.cxx | 601 + vcl/source/gdi/graphictools.cxx | 296 + vcl/source/gdi/hatch.cxx | 110 + vcl/source/gdi/impanmvw.cxx | 321 + vcl/source/gdi/impglyphitem.cxx | 78 + vcl/source/gdi/impgraph.cxx | 1882 +++ vcl/source/gdi/impvect.cxx | 1000 ++ vcl/source/gdi/impvect.hxx | 35 + vcl/source/gdi/jobset.cxx | 394 + vcl/source/gdi/lineinfo.cxx | 261 + vcl/source/gdi/mapmod.cxx | 178 + vcl/source/gdi/metaact.cxx | 3412 ++++ vcl/source/gdi/mtfxmldump.cxx | 1274 ++ vcl/source/gdi/oldprintadaptor.cxx | 112 + vcl/source/gdi/pdfbuildin_fonts.cxx | 740 + vcl/source/gdi/pdfbuildin_fonts.hxx | 81 + vcl/source/gdi/pdfextoutdevdata.cxx | 891 + vcl/source/gdi/pdffontcache.cxx | 65 + vcl/source/gdi/pdffontcache.hxx | 72 + vcl/source/gdi/pdfwriter.cxx | 467 + vcl/source/gdi/pdfwriter_impl.cxx | 11212 +++++++++++++ vcl/source/gdi/pdfwriter_impl.hxx | 1265 ++ vcl/source/gdi/pdfwriter_impl2.cxx | 1989 +++ vcl/source/gdi/print.cxx | 1639 ++ vcl/source/gdi/print2.cxx | 1314 ++ vcl/source/gdi/print3.cxx | 2118 +++ vcl/source/gdi/regband.cxx | 885 + vcl/source/gdi/region.cxx | 1778 ++ vcl/source/gdi/regionband.cxx | 1358 ++ vcl/source/gdi/salgdiimpl.cxx | 26 + vcl/source/gdi/salgdilayout.cxx | 897 + vcl/source/gdi/sallayout.cxx | 1585 ++ vcl/source/gdi/salmisc.cxx | 491 + vcl/source/gdi/scrptrun.cxx | 247 + vcl/source/gdi/svmconverter.cxx | 1245 ++ vcl/source/gdi/textlayout.cxx | 351 + vcl/source/gdi/vectorgraphicdata.cxx | 358 + vcl/source/gdi/virdev.cxx | 510 + vcl/source/gdi/wall.cxx | 366 + vcl/source/graphic/GraphicID.cxx | 103 + vcl/source/graphic/GraphicLoader.cxx | 44 + vcl/source/graphic/GraphicObject.cxx | 942 ++ vcl/source/graphic/GraphicObject2.cxx | 506 + vcl/source/graphic/GraphicReader.cxx | 29 + vcl/source/graphic/Manager.cxx | 247 + vcl/source/graphic/UnoGraphic.cxx | 192 + vcl/source/graphic/UnoGraphicDescriptor.cxx | 424 + vcl/source/graphic/UnoGraphicObject.cxx | 100 + vcl/source/graphic/UnoGraphicProvider.cxx | 837 + vcl/source/graphic/UnoGraphicTransformer.cxx | 140 + vcl/source/graphic/grfattr.cxx | 62 + vcl/source/helper/canvasbitmap.cxx | 1407 ++ vcl/source/helper/canvastools.cxx | 623 + vcl/source/helper/commandinfoprovider.cxx | 480 + vcl/source/helper/displayconnectiondispatch.cxx | 111 + vcl/source/helper/driverblocklist.cxx | 762 + vcl/source/helper/errcode.cxx | 147 + vcl/source/helper/evntpost.cxx | 57 + vcl/source/helper/lazydelete.cxx | 58 + vcl/source/helper/strhelper.cxx | 370 + vcl/source/helper/svtaccessiblefactory.cxx | 273 + vcl/source/helper/threadex.cxx | 72 + vcl/source/image/Image.cxx | 163 + vcl/source/image/ImageRepository.cxx | 37 + vcl/source/image/ImageTree.cxx | 62 + vcl/source/image/ImplImage.cxx | 156 + vcl/source/image/ImplImageTree.cxx | 698 + vcl/source/opengl/GLMHelper.hxx | 24 + vcl/source/opengl/OpenGLContext.cxx | 809 + vcl/source/opengl/OpenGLHelper.cxx | 1055 ++ vcl/source/outdev/bitmap.cxx | 1788 ++ vcl/source/outdev/clipping.cxx | 226 + vcl/source/outdev/curvedshapes.cxx | 210 + vcl/source/outdev/font.cxx | 1435 ++ vcl/source/outdev/gradient.cxx | 1045 ++ vcl/source/outdev/hatch.cxx | 409 + vcl/source/outdev/line.cxx | 304 + vcl/source/outdev/map.cxx | 1936 +++ vcl/source/outdev/mask.cxx | 154 + vcl/source/outdev/nativecontrols.cxx | 356 + vcl/source/outdev/outdev.cxx | 707 + vcl/source/outdev/outdevstate.cxx | 609 + vcl/source/outdev/pixel.cxx | 116 + vcl/source/outdev/polygon.cxx | 518 + vcl/source/outdev/polyline.cxx | 386 + vcl/source/outdev/rect.cxx | 415 + vcl/source/outdev/text.cxx | 2510 +++ vcl/source/outdev/textline.cxx | 1026 ++ vcl/source/outdev/transparent.cxx | 859 + vcl/source/outdev/vclreferencebase.cxx | 44 + vcl/source/outdev/wallpaper.cxx | 396 + vcl/source/pdf/Matrix3.cxx | 117 + vcl/source/pdf/PDFiumLibrary.cxx | 96 + vcl/source/pdf/ResourceDict.cxx | 60 + vcl/source/pdf/XmpMetadata.cxx | 190 + vcl/source/salmain/salmain.cxx | 36 + vcl/source/toolkit/README | 2 + vcl/source/toolkit/group.cxx | 257 + vcl/source/toolkit/morebtn.cxx | 123 + vcl/source/treelist/headbar.cxx | 1302 ++ vcl/source/treelist/iconview.cxx | 221 + vcl/source/treelist/iconviewimpl.cxx | 656 + vcl/source/treelist/iconviewimpl.hxx | 68 + vcl/source/treelist/imap.cxx | 994 ++ vcl/source/treelist/imap2.cxx | 531 + vcl/source/treelist/imap3.cxx | 87 + vcl/source/treelist/inetimg.cxx | 135 + vcl/source/treelist/svimpbox.cxx | 3314 ++++ vcl/source/treelist/svlbitm.cxx | 529 + vcl/source/treelist/svtabbx.cxx | 1033 ++ vcl/source/treelist/transfer.cxx | 2264 +++ vcl/source/treelist/transfer2.cxx | 519 + vcl/source/treelist/treelist.cxx | 1565 ++ vcl/source/treelist/treelistbox.cxx | 3603 ++++ vcl/source/treelist/treelistentry.cxx | 235 + vcl/source/treelist/uiobject.cxx | 179 + vcl/source/treelist/viewdataentry.cxx | 87 + vcl/source/uipreviewer/previewer.cxx | 116 + vcl/source/uitest/logger.cxx | 553 + vcl/source/uitest/uiobject.cxx | 1506 ++ vcl/source/uitest/uitest.cxx | 80 + vcl/source/uitest/uno/uiobject_uno.cxx | 210 + vcl/source/uitest/uno/uiobject_uno.hxx | 73 + vcl/source/uitest/uno/uitest_uno.cxx | 120 + vcl/source/window/EnumContext.cxx | 213 + vcl/source/window/NotebookBarAddonsMerger.cxx | 190 + vcl/source/window/OptionalBox.cxx | 63 + vcl/source/window/abstdlg.cxx | 85 + vcl/source/window/accel.cxx | 296 + vcl/source/window/accessibility.cxx | 634 + vcl/source/window/accmgr.cxx | 229 + vcl/source/window/brdwin.cxx | 2080 +++ vcl/source/window/bufferdevice.cxx | 45 + vcl/source/window/bufferdevice.hxx | 38 + vcl/source/window/builder.cxx | 4708 ++++++ vcl/source/window/clipping.cxx | 719 + vcl/source/window/commandevent.cxx | 198 + vcl/source/window/cursor.cxx | 462 + vcl/source/window/debug.cxx | 48 + vcl/source/window/debugevent.cxx | 270 + vcl/source/window/decoview.cxx | 1090 ++ vcl/source/window/dialog.cxx | 1617 ++ vcl/source/window/dlgctrl.cxx | 1157 ++ vcl/source/window/dlgctrl.hxx | 37 + vcl/source/window/dndeventdispatcher.cxx | 412 + vcl/source/window/dndlistenercontainer.cxx | 451 + vcl/source/window/dockingarea.cxx | 256 + vcl/source/window/dockmgr.cxx | 1059 ++ vcl/source/window/dockwin.cxx | 1061 ++ vcl/source/window/errinf.cxx | 319 + vcl/source/window/event.cxx | 678 + vcl/source/window/floatwin.cxx | 950 ++ vcl/source/window/globalization.cxx | 39 + vcl/source/window/introwin.cxx | 52 + vcl/source/window/keycod.cxx | 108 + vcl/source/window/keyevent.cxx | 67 + vcl/source/window/layout.cxx | 2882 ++++ vcl/source/window/legacyaccessibility.cxx | 242 + vcl/source/window/menu.cxx | 3100 ++++ vcl/source/window/menubarwindow.cxx | 1252 ++ vcl/source/window/menubarwindow.hxx | 148 + vcl/source/window/menufloatingwindow.cxx | 1334 ++ vcl/source/window/menufloatingwindow.hxx | 130 + vcl/source/window/menuitemlist.cxx | 318 + vcl/source/window/menuitemlist.hxx | 149 + vcl/source/window/menuwindow.cxx | 111 + vcl/source/window/menuwindow.hxx | 58 + vcl/source/window/mnemonic.cxx | 343 + vcl/source/window/mnemonicengine.cxx | 108 + vcl/source/window/mouse.cxx | 792 + vcl/source/window/paint.cxx | 1844 +++ vcl/source/window/popupmenuwindow.cxx | 74 + vcl/source/window/printdlg.cxx | 2239 +++ vcl/source/window/scrwnd.cxx | 390 + vcl/source/window/seleng.cxx | 411 + vcl/source/window/settings.cxx | 266 + vcl/source/window/split.cxx | 701 + vcl/source/window/splitwin.cxx | 2757 ++++ vcl/source/window/stacking.cxx | 1162 ++ vcl/source/window/status.cxx | 1473 ++ vcl/source/window/syschild.cxx | 187 + vcl/source/window/syswin.cxx | 1199 ++ vcl/source/window/tabdlg.cxx | 184 + vcl/source/window/tabpage.cxx | 202 + vcl/source/window/taskpanelist.cxx | 286 + vcl/source/window/toolbox.cxx | 4902 ++++++ vcl/source/window/toolbox2.cxx | 1778 ++ vcl/source/window/window.cxx | 3926 +++++ vcl/source/window/window2.cxx | 1984 +++ vcl/source/window/window3.cxx | 68 + vcl/source/window/winproc.cxx | 2634 +++ vcl/source/window/wrkwin.cxx | 280 + vcl/uiconfig/theme_definitions/ios/arrow-down.svg | 5 + vcl/uiconfig/theme_definitions/ios/arrow-up.svg | 5 + .../ios/combobox-button-disabled.svg | 4 + .../theme_definitions/ios/combobox-button.svg | 4 + .../theme_definitions/ios/combobox-disabled.svg | 3 + vcl/uiconfig/theme_definitions/ios/combobox.svg | 3 + .../theme_definitions/ios/common-rect-disabled.svg | 3 + .../ios/common-rect-focus-slim.svg | 3 + .../theme_definitions/ios/common-rect-focus.svg | 3 + vcl/uiconfig/theme_definitions/ios/common-rect.svg | 3 + vcl/uiconfig/theme_definitions/ios/definition.xml | 530 + .../theme_definitions/ios/pushbutton-default.svg | 3 + .../theme_definitions/ios/pushbutton-disabled.svg | 3 + .../theme_definitions/ios/pushbutton-rollover.svg | 3 + .../theme_definitions/ios/scrollbar-horizontal.svg | 4 + .../theme_definitions/ios/scrollbar-vertical.svg | 4 + .../ios/slider-button-disabled.svg | 3 + .../theme_definitions/ios/slider-button.svg | 3 + .../ios/spinbox-left-disabled.svg | 4 + .../theme_definitions/ios/spinbox-left-pressed.svg | 5 + .../theme_definitions/ios/spinbox-left.svg | 4 + .../ios/spinbox-right-disabled.svg | 5 + .../ios/spinbox-right-pressed.svg | 6 + .../theme_definitions/ios/spinbox-right.svg | 5 + .../theme_definitions/ios/switch-off-disabled.svg | 14 + .../theme_definitions/ios/switch-off-pressed.svg | 15 + vcl/uiconfig/theme_definitions/ios/switch-off.svg | 15 + .../theme_definitions/ios/switch-on-disabled.svg | 15 + .../theme_definitions/ios/switch-on-pressed.svg | 11 + vcl/uiconfig/theme_definitions/ios/switch-on.svg | 15 + .../ios/tabitem-first-selected.svg | 3 + .../theme_definitions/ios/tabitem-first.svg | 3 + .../ios/tabitem-last-selected.svg | 3 + .../theme_definitions/ios/tabitem-last.svg | 3 + .../ios/tabitem-middle-selected.svg | 3 + .../theme_definitions/ios/tabitem-middle.svg | 3 + .../theme_definitions/ios/tick-off-disabled.svg | 4 + .../theme_definitions/ios/tick-off-pressed.svg | 11 + vcl/uiconfig/theme_definitions/ios/tick-off.svg | 13 + .../theme_definitions/ios/tick-on-disabled.svg | 11 + .../theme_definitions/ios/tick-on-pressed.svg | 11 + vcl/uiconfig/theme_definitions/ios/tick-on.svg | 13 + vcl/uiconfig/ui/aboutbox.ui | 135 + vcl/uiconfig/ui/combobox.ui | 124 + vcl/uiconfig/ui/cupspassworddialog.ui | 181 + vcl/uiconfig/ui/editmenu.ui | 77 + vcl/uiconfig/ui/errornocontentdialog.ui | 35 + vcl/uiconfig/ui/errornoprinterdialog.ui | 38 + vcl/uiconfig/ui/moreoptionsdialog.ui | 94 + vcl/uiconfig/ui/printdialog.ui | 1295 ++ vcl/uiconfig/ui/printerdevicepage.ui | 264 + vcl/uiconfig/ui/printerpaperpage.ui | 130 + vcl/uiconfig/ui/printerpropertiesdialog.ui | 176 + vcl/uiconfig/ui/printprogressdialog.ui | 85 + vcl/uiconfig/ui/querydialog.ui | 111 + vcl/uiconfig/ui/screenshotparent.ui | 54 + vcl/uiconfig/ui/wizard.ui | 17 + vcl/unx/generic/app/gendata.cxx | 44 + vcl/unx/generic/app/gendisp.cxx | 69 + vcl/unx/generic/app/geninst.cxx | 77 + vcl/unx/generic/app/gensys.cxx | 116 + vcl/unx/generic/app/i18n_cb.cxx | 494 + vcl/unx/generic/app/i18n_ic.cxx | 604 + vcl/unx/generic/app/i18n_im.cxx | 410 + vcl/unx/generic/app/i18n_keysym.cxx | 358 + vcl/unx/generic/app/i18n_xkb.cxx | 107 + vcl/unx/generic/app/keysymnames.cxx | 507 + vcl/unx/generic/app/randrwrapper.cxx | 181 + vcl/unx/generic/app/saldata.cxx | 782 + vcl/unx/generic/app/saldisp.cxx | 2889 ++++ vcl/unx/generic/app/salinst.cxx | 249 + vcl/unx/generic/app/saltimer.cxx | 68 + vcl/unx/generic/app/sm.cxx | 858 + vcl/unx/generic/app/wmadaptor.cxx | 2308 +++ vcl/unx/generic/desktopdetect/desktopdetector.cxx | 253 + vcl/unx/generic/dtrans/X11_clipboard.cxx | 231 + vcl/unx/generic/dtrans/X11_clipboard.hxx | 114 + vcl/unx/generic/dtrans/X11_dndcontext.cxx | 118 + vcl/unx/generic/dtrans/X11_dndcontext.hxx | 83 + vcl/unx/generic/dtrans/X11_droptarget.cxx | 177 + vcl/unx/generic/dtrans/X11_selection.cxx | 4157 +++++ vcl/unx/generic/dtrans/X11_selection.hxx | 501 + vcl/unx/generic/dtrans/X11_service.cxx | 84 + vcl/unx/generic/dtrans/X11_transferable.cxx | 101 + vcl/unx/generic/dtrans/X11_transferable.hxx | 53 + vcl/unx/generic/dtrans/bmp.cxx | 786 + vcl/unx/generic/dtrans/bmp.hxx | 78 + vcl/unx/generic/dtrans/config.cxx | 123 + vcl/unx/generic/dtrans/copydata_curs.h | 36 + vcl/unx/generic/dtrans/copydata_mask.h | 36 + vcl/unx/generic/dtrans/linkdata_curs.h | 36 + vcl/unx/generic/dtrans/linkdata_mask.h | 36 + vcl/unx/generic/dtrans/movedata_curs.h | 36 + vcl/unx/generic/dtrans/movedata_mask.h | 36 + vcl/unx/generic/dtrans/nodrop_curs.h | 36 + vcl/unx/generic/dtrans/nodrop_mask.h | 36 + vcl/unx/generic/fontmanager/fontconfig.cxx | 1198 ++ vcl/unx/generic/fontmanager/fontmanager.cxx | 1176 ++ vcl/unx/generic/fontmanager/fontsubst.cxx | 221 + vcl/unx/generic/fontmanager/helper.cxx | 262 + vcl/unx/generic/gdi/cairo_xlib_cairo.cxx | 314 + vcl/unx/generic/gdi/cairo_xlib_cairo.hxx | 98 + vcl/unx/generic/gdi/cairotextrender.cxx | 309 + vcl/unx/generic/gdi/font.cxx | 124 + vcl/unx/generic/gdi/freetypetextrender.cxx | 237 + vcl/unx/generic/gdi/gdiimpl.cxx | 1993 +++ vcl/unx/generic/gdi/gdiimpl.hxx | 296 + vcl/unx/generic/gdi/nativewindowhandleprovider.cxx | 17 + vcl/unx/generic/gdi/salbmp.cxx | 1036 ++ vcl/unx/generic/gdi/salgdi.cxx | 799 + vcl/unx/generic/gdi/salgdi2.cxx | 181 + vcl/unx/generic/gdi/salvd.cxx | 237 + vcl/unx/generic/gdi/x11cairotextrender.cxx | 90 + vcl/unx/generic/gdi/xrender_peer.cxx | 48 + vcl/unx/generic/glyphs/freetype_glyphcache.cxx | 951 ++ vcl/unx/generic/glyphs/glyphcache.cxx | 119 + vcl/unx/generic/print/bitmap_gfx.cxx | 696 + vcl/unx/generic/print/common_gfx.cxx | 1148 ++ vcl/unx/generic/print/genprnpsp.cxx | 1300 ++ vcl/unx/generic/print/genpspgraphics.cxx | 1006 ++ vcl/unx/generic/print/glyphset.cxx | 301 + vcl/unx/generic/print/glyphset.hxx | 82 + vcl/unx/generic/print/printerjob.cxx | 973 ++ vcl/unx/generic/print/prtsetup.cxx | 507 + vcl/unx/generic/print/prtsetup.hxx | 137 + vcl/unx/generic/print/psheader.ps | 363 + vcl/unx/generic/print/psputil.cxx | 184 + vcl/unx/generic/print/psputil.hxx | 54 + vcl/unx/generic/print/text_gfx.cxx | 158 + vcl/unx/generic/printer/configuration/README | 5 + .../generic/printer/configuration/ppds/SGENPRT.PS | 582 + vcl/unx/generic/printer/configuration/psprint.conf | 99 + vcl/unx/generic/printer/cpdmgr.cxx | 754 + vcl/unx/generic/printer/cupsmgr.cxx | 965 ++ vcl/unx/generic/printer/jobdata.cxx | 306 + vcl/unx/generic/printer/ppdparser.cxx | 1987 +++ vcl/unx/generic/printer/printerinfomanager.cxx | 900 + vcl/unx/generic/window/salframe.cxx | 4107 +++++ vcl/unx/generic/window/salobj.cxx | 506 + vcl/unx/generic/window/screensaverinhibitor.cxx | 370 + vcl/unx/glxtest.cxx | 294 + vcl/unx/gtk3/a11y/TODO | 49 + vcl/unx/gtk3/a11y/atkfactory.hxx | 33 + vcl/unx/gtk3/a11y/atklistener.hxx | 71 + vcl/unx/gtk3/a11y/atkregistry.hxx | 35 + vcl/unx/gtk3/a11y/atktextattributes.hxx | 52 + vcl/unx/gtk3/a11y/atkutil.hxx | 29 + vcl/unx/gtk3/a11y/atkwrapper.hxx | 125 + vcl/unx/gtk3/a11y/gtk3atkaction.cxx | 275 + vcl/unx/gtk3/a11y/gtk3atkbridge.cxx | 34 + vcl/unx/gtk3/a11y/gtk3atkcomponent.cxx | 387 + vcl/unx/gtk3/a11y/gtk3atkeditabletext.cxx | 193 + vcl/unx/gtk3/a11y/gtk3atkfactory.cxx | 186 + vcl/unx/gtk3/a11y/gtk3atkhypertext.cxx | 277 + vcl/unx/gtk3/a11y/gtk3atkimage.cxx | 131 + vcl/unx/gtk3/a11y/gtk3atklistener.cxx | 748 + vcl/unx/gtk3/a11y/gtk3atkregistry.cxx | 66 + vcl/unx/gtk3/a11y/gtk3atkselection.cxx | 190 + vcl/unx/gtk3/a11y/gtk3atktable.cxx | 580 + vcl/unx/gtk3/a11y/gtk3atktext.cxx | 897 + vcl/unx/gtk3/a11y/gtk3atktextattributes.cxx | 1390 ++ vcl/unx/gtk3/a11y/gtk3atkutil.cxx | 708 + vcl/unx/gtk3/a11y/gtk3atkvalue.cxx | 138 + vcl/unx/gtk3/a11y/gtk3atkwrapper.cxx | 942 ++ vcl/unx/gtk3/cairo_gtk3_cairo.cxx | 128 + vcl/unx/gtk3/cairo_gtk3_cairo.hxx | 49 + vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx | 1991 +++ vcl/unx/gtk3/fpicker/SalGtkFilePicker.hxx | 240 + vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx | 177 + vcl/unx/gtk3/fpicker/SalGtkFolderPicker.hxx | 66 + vcl/unx/gtk3/fpicker/SalGtkPicker.cxx | 266 + vcl/unx/gtk3/fpicker/SalGtkPicker.hxx | 117 + vcl/unx/gtk3/fpicker/eventnotification.hxx | 43 + vcl/unx/gtk3/fpicker/resourceprovider.cxx | 80 + vcl/unx/gtk3/gtk3gloactiongroup.cxx | 405 + vcl/unx/gtk3/gtk3glomenu.cxx | 692 + vcl/unx/gtk3/gtk3gtkdata.cxx | 778 + vcl/unx/gtk3/gtk3gtkframe.cxx | 4609 ++++++ vcl/unx/gtk3/gtk3gtkinst.cxx | 16272 +++++++++++++++++++ vcl/unx/gtk3/gtk3gtkobject.cxx | 463 + vcl/unx/gtk3/gtk3gtkprintwrapper.cxx | 153 + vcl/unx/gtk3/gtk3gtksalmenu.cxx | 1409 ++ vcl/unx/gtk3/gtk3gtksys.cxx | 275 + vcl/unx/gtk3/gtk3hudawareness.cxx | 110 + vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx | 3731 +++++ vcl/unx/gtk3/gtk3salprn-gtk.cxx | 954 ++ vcl/unx/gtk3/gtkprintwrapper.hxx | 17 + vcl/unx/gtk3_kde5/FPServiceInfo.hxx | 28 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkaction.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkbridge.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkcomponent.cxx | 12 + .../gtk3_kde5/a11y/gtk3_kde5_atkeditabletext.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkfactory.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkhypertext.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkimage.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atklistener.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkregistry.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkselection.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktable.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktext.cxx | 12 + .../gtk3_kde5/a11y/gtk3_kde5_atktextattributes.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkutil.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkvalue.cxx | 12 + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkwrapper.cxx | 12 + vcl/unx/gtk3_kde5/filepicker_ipc_commands.hxx | 173 + vcl/unx/gtk3_kde5/gtk3_kde5_a11y.cxx | 38 + vcl/unx/gtk3_kde5/gtk3_kde5_cairo.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker.cxx | 456 + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker.hxx | 131 + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc.cxx | 275 + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc.hxx | 134 + vcl/unx/gtk3_kde5/gtk3_kde5_folderpicker.cxx | 85 + vcl/unx/gtk3_kde5/gtk3_kde5_folderpicker.hxx | 59 + vcl/unx/gtk3_kde5/gtk3_kde5_gloactiongroup.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_glomenu.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_gtkdata.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_gtkframe.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_gtkinst.cxx | 57 + vcl/unx/gtk3_kde5/gtk3_kde5_gtkobject.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_gtksalmenu.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_gtksys.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_hudawareness.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_printwrapper.cxx | 22 + .../gtk3_kde5/gtk3_kde5_salnativewidgets-gtk.cxx | 22 + vcl/unx/gtk3_kde5/gtk3_kde5_salprn-gtk.cxx | 22 + vcl/unx/gtk3_kde5/kde5_filepicker.cxx | 292 + vcl/unx/gtk3_kde5/kde5_filepicker.hxx | 110 + vcl/unx/gtk3_kde5/kde5_filepicker_ipc.cxx | 374 + vcl/unx/gtk3_kde5/kde5_filepicker_ipc.hxx | 51 + vcl/unx/gtk3_kde5/kde5_lo_filepicker_main.cxx | 53 + vcl/unx/kf5/KF5FilePicker.cxx | 180 + vcl/unx/kf5/KF5FilePicker.hxx | 63 + vcl/unx/kf5/KF5SalFrame.cxx | 188 + vcl/unx/kf5/KF5SalFrame.hxx | 43 + vcl/unx/kf5/KF5SalInstance.cxx | 101 + vcl/unx/kf5/KF5SalInstance.hxx | 36 + vcl/unx/x11/x11sys.cxx | 105 + vcl/unx/x11/xlimits.cxx | 29 + vcl/vcl.android.component | 31 + vcl/vcl.common.component | 30 + vcl/vcl.headless.component | 28 + vcl/vcl.ios.component | 31 + vcl/vcl.macosx.component | 41 + vcl/vcl.unx.component | 41 + vcl/vcl.windows.component | 32 + vcl/win/app/saldata.cxx | 78 + vcl/win/app/salinfo.cxx | 176 + vcl/win/app/salinst.cxx | 1095 ++ vcl/win/app/salshl.cxx | 112 + vcl/win/app/saltimer.cxx | 199 + vcl/win/gdi/DWriteTextRenderer.cxx | 413 + vcl/win/gdi/gdiimpl.cxx | 2710 +++ vcl/win/gdi/gdiimpl.hxx | 250 + vcl/win/gdi/salbmp.cxx | 1067 ++ vcl/win/gdi/salfont.cxx | 1766 ++ vcl/win/gdi/salgdi.cxx | 1058 ++ vcl/win/gdi/salgdi2.cxx | 248 + vcl/win/gdi/salgdi_gdiplus.cxx | 98 + vcl/win/gdi/salnativewidgets-luna.cxx | 1559 ++ vcl/win/gdi/salprn.cxx | 1629 ++ vcl/win/gdi/salvd.cxx | 226 + vcl/win/gdi/winlayout.cxx | 635 + vcl/win/src/50.bmp | Bin 0 -> 94 bytes vcl/win/src/50.png | Bin 0 -> 125 bytes vcl/win/src/ase.cur | Bin 0 -> 326 bytes vcl/win/src/asn.cur | Bin 0 -> 326 bytes vcl/win/src/asne.cur | Bin 0 -> 326 bytes vcl/win/src/asns.cur | Bin 0 -> 326 bytes vcl/win/src/asnswe.cur | Bin 0 -> 326 bytes vcl/win/src/asnw.cur | Bin 0 -> 326 bytes vcl/win/src/ass.cur | Bin 0 -> 326 bytes vcl/win/src/asse.cur | Bin 0 -> 326 bytes vcl/win/src/assw.cur | Bin 0 -> 326 bytes vcl/win/src/asw.cur | Bin 0 -> 326 bytes vcl/win/src/aswe.cur | Bin 0 -> 326 bytes vcl/win/src/chain.cur | Bin 0 -> 326 bytes vcl/win/src/chainnot.cur | Bin 0 -> 326 bytes vcl/win/src/chart.cur | Bin 0 -> 326 bytes vcl/win/src/copydata.cur | Bin 0 -> 326 bytes vcl/win/src/copydlnk.cur | Bin 0 -> 326 bytes vcl/win/src/copyf.cur | Bin 0 -> 326 bytes vcl/win/src/copyf2.cur | Bin 0 -> 326 bytes vcl/win/src/copyflnk.cur | Bin 0 -> 326 bytes vcl/win/src/crook.cur | Bin 0 -> 326 bytes vcl/win/src/crop.cur | Bin 0 -> 326 bytes vcl/win/src/darc.cur | Bin 0 -> 326 bytes vcl/win/src/dbezier.cur | Bin 0 -> 326 bytes vcl/win/src/dcapt.cur | Bin 0 -> 326 bytes vcl/win/src/dcirccut.cur | Bin 0 -> 326 bytes vcl/win/src/dconnect.cur | Bin 0 -> 326 bytes vcl/win/src/dellipse.cur | Bin 0 -> 326 bytes vcl/win/src/detectiv.cur | Bin 0 -> 326 bytes vcl/win/src/dfree.cur | Bin 0 -> 326 bytes vcl/win/src/dline.cur | Bin 0 -> 326 bytes vcl/win/src/dpie.cur | Bin 0 -> 326 bytes vcl/win/src/dpolygon.cur | Bin 0 -> 326 bytes vcl/win/src/drect.cur | Bin 0 -> 326 bytes vcl/win/src/dtext.cur | Bin 0 -> 326 bytes vcl/win/src/fill.cur | Bin 0 -> 326 bytes vcl/win/src/hshear.cur | Bin 0 -> 326 bytes vcl/win/src/linkdata.cur | Bin 0 -> 326 bytes vcl/win/src/linkf.cur | Bin 0 -> 326 bytes vcl/win/src/magnify.cur | Bin 0 -> 326 bytes vcl/win/src/mirror.cur | Bin 0 -> 326 bytes vcl/win/src/movebw.cur | Bin 0 -> 326 bytes vcl/win/src/movedata.cur | Bin 0 -> 326 bytes vcl/win/src/movedlnk.cur | Bin 0 -> 326 bytes vcl/win/src/movef.cur | Bin 0 -> 326 bytes vcl/win/src/movef2.cur | Bin 0 -> 326 bytes vcl/win/src/moveflnk.cur | Bin 0 -> 326 bytes vcl/win/src/movept.cur | Bin 0 -> 326 bytes vcl/win/src/nullptr.cur | Bin 0 -> 326 bytes vcl/win/src/pivotcol.cur | Bin 0 -> 326 bytes vcl/win/src/pivotdel.cur | Bin 0 -> 326 bytes vcl/win/src/pivotfld.cur | Bin 0 -> 326 bytes vcl/win/src/pivotrow.cur | Bin 0 -> 326 bytes vcl/win/src/rotate.cur | Bin 0 -> 326 bytes vcl/win/src/salsrc.rc | 89 + vcl/win/src/sd.ico | Bin 0 -> 3310 bytes vcl/win/src/tblsele.cur | Bin 0 -> 326 bytes vcl/win/src/tblsels.cur | Bin 0 -> 326 bytes vcl/win/src/tblselse.cur | Bin 0 -> 326 bytes vcl/win/src/tblselsw.cur | Bin 0 -> 326 bytes vcl/win/src/tblselw.cur | Bin 0 -> 326 bytes vcl/win/src/vshear.cur | Bin 0 -> 326 bytes vcl/win/src/vtext.cur | Bin 0 -> 326 bytes vcl/win/src/wshide.cur | Bin 0 -> 326 bytes vcl/win/src/wsshow.cur | Bin 0 -> 326 bytes vcl/win/window/keynames.cxx | 224 + vcl/win/window/salframe.cxx | 5925 +++++++ vcl/win/window/salmenu.cxx | 355 + vcl/win/window/salobj.cxx | 727 + vcl/workben/602fuzzer.cxx | 57 + vcl/workben/602fuzzer.options | 2 + vcl/workben/bmpfuzzer.cxx | 56 + vcl/workben/bmpfuzzer.options | 2 + vcl/workben/cgmfuzzer.cxx | 129 + vcl/workben/cgmfuzzer.options | 4 + vcl/workben/commonfuzzer.hxx | 143 + vcl/workben/diffuzzer.cxx | 86 + vcl/workben/diffuzzer.options | 4 + vcl/workben/docxfuzzer.cxx | 39 + vcl/workben/docxfuzzer.options | 4 + vcl/workben/dxffuzzer.cxx | 67 + vcl/workben/dxffuzzer.options | 2 + vcl/workben/epsfuzzer.cxx | 67 + vcl/workben/epsfuzzer.options | 2 + vcl/workben/fftester.cxx | 692 + vcl/workben/fodpfuzzer.cxx | 39 + vcl/workben/fodpfuzzer.options | 5 + vcl/workben/fodsfuzzer.cxx | 34 + vcl/workben/fodsfuzzer.options | 5 + vcl/workben/fodtfuzzer.cxx | 39 + vcl/workben/fodtfuzzer.options | 5 + vcl/workben/giffuzzer.cxx | 56 + vcl/workben/giffuzzer.options | 3 + vcl/workben/htmlfuzzer.cxx | 33 + vcl/workben/htmlfuzzer.options | 3 + vcl/workben/hwpfuzzer.cxx | 57 + vcl/workben/hwpfuzzer.options | 2 + vcl/workben/icontest.cxx | 219 + vcl/workben/jpgfuzzer.cxx | 56 + vcl/workben/jpgfuzzer.options | 3 + vcl/workben/localestub/localedata_en_AU.cxx | 1263 ++ vcl/workben/localestub/localedata_en_BW.cxx | 140 + vcl/workben/localestub/localedata_en_BZ.cxx | 225 + vcl/workben/localestub/localedata_en_CA.cxx | 929 ++ vcl/workben/localestub/localedata_en_GB.cxx | 912 ++ vcl/workben/localestub/localedata_en_GH.cxx | 1526 ++ vcl/workben/localestub/localedata_en_GM.cxx | 140 + vcl/workben/localestub/localedata_en_IE.cxx | 259 + vcl/workben/localestub/localedata_en_IN.cxx | 200 + vcl/workben/localestub/localedata_en_JM.cxx | 1263 ++ vcl/workben/localestub/localedata_en_LK.cxx | 144 + vcl/workben/localestub/localedata_en_MW.cxx | 140 + vcl/workben/localestub/localedata_en_MY.cxx | 118 + vcl/workben/localestub/localedata_en_NA.cxx | 1280 ++ vcl/workben/localestub/localedata_en_NG.cxx | 142 + vcl/workben/localestub/localedata_en_NZ.cxx | 563 + vcl/workben/localestub/localedata_en_PH.cxx | 140 + vcl/workben/localestub/localedata_en_TT.cxx | 563 + vcl/workben/localestub/localedata_en_US.cxx | 2609 +++ vcl/workben/localestub/localedata_en_ZA.cxx | 1263 ++ vcl/workben/localestub/localedata_en_ZM.cxx | 142 + vcl/workben/localestub/localedata_en_ZW.cxx | 563 + vcl/workben/localestub/localestub.cxx | 39 + vcl/workben/lwpfuzzer.cxx | 57 + vcl/workben/lwpfuzzer.options | 2 + vcl/workben/metfuzzer.cxx | 67 + vcl/workben/metfuzzer.options | 4 + vcl/workben/mmlfuzzer.cxx | 29 + vcl/workben/mmlfuzzer.options | 5 + vcl/workben/mtfdemo.cxx | 165 + vcl/workben/mtpfuzzer.cxx | 42 + vcl/workben/mtpfuzzer.options | 2 + vcl/workben/olefuzzer.cxx | 65 + vcl/workben/olefuzzer.options | 2 + vcl/workben/pcdfuzzer.cxx | 58 + vcl/workben/pcdfuzzer.options | 2 + vcl/workben/pctfuzzer.cxx | 58 + vcl/workben/pctfuzzer.options | 2 + vcl/workben/pcxfuzzer.cxx | 58 + vcl/workben/pcxfuzzer.options | 2 + vcl/workben/pngfuzzer.cxx | 56 + vcl/workben/pngfuzzer.options | 3 + vcl/workben/ppmfuzzer.cxx | 58 + vcl/workben/ppmfuzzer.options | 2 + vcl/workben/pptfuzzer.cxx | 135 + vcl/workben/pptfuzzer.options | 2 + vcl/workben/pptxfuzzer.cxx | 33 + vcl/workben/pptxfuzzer.options | 4 + vcl/workben/psdfuzzer.cxx | 58 + vcl/workben/psdfuzzer.options | 2 + vcl/workben/qpwfuzzer.cxx | 89 + vcl/workben/qpwfuzzer.options | 4 + vcl/workben/rasfuzzer.cxx | 58 + vcl/workben/rasfuzzer.options | 2 + vcl/workben/rtffuzzer.cxx | 90 + vcl/workben/rtffuzzer.options | 4 + vcl/workben/scrtffuzzer.cxx | 83 + vcl/workben/scrtffuzzer.options | 4 + vcl/workben/sftfuzzer.cxx | 44 + vcl/workben/sftfuzzer.options | 2 + vcl/workben/slkfuzzer.cxx | 89 + vcl/workben/slkfuzzer.options | 4 + vcl/workben/svdem.cxx | 98 + vcl/workben/svmfuzzer.cxx | 56 + vcl/workben/svmfuzzer.options | 2 + vcl/workben/svpclient.cxx | 283 + vcl/workben/svptest.cxx | 328 + vcl/workben/tgafuzzer.cxx | 58 + vcl/workben/tgafuzzer.options | 2 + vcl/workben/tiffuzzer.cxx | 64 + vcl/workben/tiffuzzer.options | 3 + vcl/workben/vcldemo.cxx | 2450 +++ vcl/workben/wksfuzzer.cxx | 53 + vcl/workben/wksfuzzer.options | 2 + vcl/workben/wmffuzzer.cxx | 68 + vcl/workben/wmffuzzer.options | 2 + vcl/workben/ww2fuzzer.cxx | 104 + vcl/workben/ww2fuzzer.options | 4 + vcl/workben/ww6fuzzer.cxx | 106 + vcl/workben/ww6fuzzer.options | 4 + vcl/workben/ww8fuzzer.cxx | 106 + vcl/workben/ww8fuzzer.options | 4 + vcl/workben/xbmfuzzer.cxx | 56 + vcl/workben/xbmfuzzer.options | 2 + vcl/workben/xlsfuzzer.cxx | 53 + vcl/workben/xlsfuzzer.options | 4 + vcl/workben/xlsxfuzzer.cxx | 31 + vcl/workben/xlsxfuzzer.options | 4 + vcl/workben/xpmfuzzer.cxx | 56 + vcl/workben/xpmfuzzer.options | 2 + 1982 files changed, 537161 insertions(+) create mode 100644 vcl/AllLangMoTarget_vcl.mk create mode 100644 vcl/CppunitTest_vcl_apitests.mk create mode 100644 vcl/CppunitTest_vcl_app_test.mk create mode 100644 vcl/CppunitTest_vcl_backend_test.mk create mode 100644 vcl/CppunitTest_vcl_bitmap_render_test.mk create mode 100644 vcl/CppunitTest_vcl_bitmap_test.mk create mode 100644 vcl/CppunitTest_vcl_bitmapprocessor_test.mk create mode 100644 vcl/CppunitTest_vcl_blocklistparser_test.mk create mode 100644 vcl/CppunitTest_vcl_complextext.mk create mode 100644 vcl/CppunitTest_vcl_dialogs_test.mk create mode 100644 vcl/CppunitTest_vcl_errorhandler.mk create mode 100644 vcl/CppunitTest_vcl_filter_ipdf.mk create mode 100644 vcl/CppunitTest_vcl_filters_test.mk create mode 100644 vcl/CppunitTest_vcl_font.mk create mode 100644 vcl/CppunitTest_vcl_fontcharmap.mk create mode 100644 vcl/CppunitTest_vcl_fontfeature.mk create mode 100644 vcl/CppunitTest_vcl_fontmetric.mk create mode 100644 vcl/CppunitTest_vcl_gen.mk create mode 100644 vcl/CppunitTest_vcl_graphic_test.mk create mode 100644 vcl/CppunitTest_vcl_jpeg_read_write_test.mk create mode 100644 vcl/CppunitTest_vcl_lifecycle.mk create mode 100644 vcl/CppunitTest_vcl_mnemonic.mk create mode 100644 vcl/CppunitTest_vcl_outdev.mk create mode 100644 vcl/CppunitTest_vcl_pdfexport.mk create mode 100644 vcl/CppunitTest_vcl_png_test.mk create mode 100644 vcl/CppunitTest_vcl_svm_test.mk create mode 100644 vcl/CppunitTest_vcl_timer.mk create mode 100644 vcl/CppunitTest_vcl_type_serializer_test.mk create mode 100644 vcl/CppunitTest_vcl_widget_definition_reader_test.mk create mode 100644 vcl/CustomTarget_gtk3_kde5_moc.mk create mode 100644 vcl/CustomTarget_kf5_moc.mk create mode 100644 vcl/CustomTarget_nativecalc.mk create mode 100644 vcl/CustomTarget_nativecore.mk create mode 100644 vcl/CustomTarget_nativedraw.mk create mode 100644 vcl/CustomTarget_nativemath.mk create mode 100644 vcl/CustomTarget_nativewriter.mk create mode 100644 vcl/CustomTarget_qt5_moc.mk create mode 100644 vcl/Executable_602fuzzer.mk create mode 100644 vcl/Executable_bmpfuzzer.mk create mode 100644 vcl/Executable_cgmfuzzer.mk create mode 100644 vcl/Executable_diffuzzer.mk create mode 100644 vcl/Executable_docxfuzzer.mk create mode 100644 vcl/Executable_dxffuzzer.mk create mode 100644 vcl/Executable_epsfuzzer.mk create mode 100644 vcl/Executable_fftester.mk create mode 100644 vcl/Executable_fodpfuzzer.mk create mode 100644 vcl/Executable_fodsfuzzer.mk create mode 100644 vcl/Executable_fodtfuzzer.mk create mode 100644 vcl/Executable_giffuzzer.mk create mode 100644 vcl/Executable_htmlfuzzer.mk create mode 100644 vcl/Executable_hwpfuzzer.mk create mode 100644 vcl/Executable_icontest.mk create mode 100644 vcl/Executable_jpgfuzzer.mk create mode 100644 vcl/Executable_lo_kde5filepicker.mk create mode 100644 vcl/Executable_lwpfuzzer.mk create mode 100644 vcl/Executable_metfuzzer.mk create mode 100644 vcl/Executable_mmlfuzzer.mk create mode 100644 vcl/Executable_mtfdemo.mk create mode 100644 vcl/Executable_mtpfuzzer.mk create mode 100644 vcl/Executable_olefuzzer.mk create mode 100644 vcl/Executable_pcdfuzzer.mk create mode 100644 vcl/Executable_pctfuzzer.mk create mode 100644 vcl/Executable_pcxfuzzer.mk create mode 100644 vcl/Executable_pngfuzzer.mk create mode 100644 vcl/Executable_ppmfuzzer.mk create mode 100644 vcl/Executable_pptfuzzer.mk create mode 100644 vcl/Executable_pptxfuzzer.mk create mode 100644 vcl/Executable_psdfuzzer.mk create mode 100644 vcl/Executable_qpwfuzzer.mk create mode 100644 vcl/Executable_rasfuzzer.mk create mode 100644 vcl/Executable_rtffuzzer.mk create mode 100644 vcl/Executable_scrtffuzzer.mk create mode 100644 vcl/Executable_sftfuzzer.mk create mode 100644 vcl/Executable_slkfuzzer.mk create mode 100644 vcl/Executable_svdemo.mk create mode 100644 vcl/Executable_svmfuzzer.mk create mode 100644 vcl/Executable_svpclient.mk create mode 100644 vcl/Executable_svptest.mk create mode 100644 vcl/Executable_tgafuzzer.mk create mode 100644 vcl/Executable_tiffuzzer.mk create mode 100644 vcl/Executable_ui-previewer.mk create mode 100644 vcl/Executable_vcldemo.mk create mode 100644 vcl/Executable_visualbackendtest.mk create mode 100644 vcl/Executable_wksfuzzer.mk create mode 100644 vcl/Executable_wmffuzzer.mk create mode 100644 vcl/Executable_ww2fuzzer.mk create mode 100644 vcl/Executable_ww6fuzzer.mk create mode 100644 vcl/Executable_ww8fuzzer.mk create mode 100644 vcl/Executable_xbmfuzzer.mk create mode 100644 vcl/Executable_xlsfuzzer.mk create mode 100644 vcl/Executable_xlsxfuzzer.mk create mode 100644 vcl/Executable_xpmfuzzer.mk create mode 100644 vcl/IwyuFilter_vcl.yaml create mode 100644 vcl/Library_desktop_detector.mk create mode 100644 vcl/Library_vcl.mk create mode 100644 vcl/Library_vclplug_gen.mk create mode 100644 vcl/Library_vclplug_gtk3.mk create mode 100644 vcl/Library_vclplug_gtk3_kde5.mk create mode 100644 vcl/Library_vclplug_kf5.mk create mode 100644 vcl/Library_vclplug_osx.mk create mode 100644 vcl/Library_vclplug_qt5.mk create mode 100644 vcl/Library_vclplug_win.mk create mode 100644 vcl/Makefile create mode 100644 vcl/Module_vcl.mk create mode 100644 vcl/Package_fontunxppds.mk create mode 100644 vcl/Package_fontunxpsprint.mk create mode 100644 vcl/Package_opengl_blacklist.mk create mode 100644 vcl/Package_opengl_shader.mk create mode 100644 vcl/Package_osxres.mk create mode 100644 vcl/Package_skia_blacklist.mk create mode 100644 vcl/Package_theme_definitions.mk create mode 100644 vcl/Package_tipoftheday.mk create mode 100644 vcl/README create mode 100644 vcl/README.GDIMetaFile create mode 100644 vcl/README.lifecycle create mode 100644 vcl/README.scheduler create mode 100644 vcl/README.vars create mode 100644 vcl/StaticLibrary_fuzzer_calc.mk create mode 100644 vcl/StaticLibrary_fuzzer_core.mk create mode 100644 vcl/StaticLibrary_fuzzer_draw.mk create mode 100644 vcl/StaticLibrary_fuzzer_math.mk create mode 100644 vcl/StaticLibrary_fuzzer_writer.mk create mode 100644 vcl/StaticLibrary_fuzzerstubs.mk create mode 100644 vcl/StaticLibrary_glxtest.mk create mode 100644 vcl/StaticLibrary_vclmain.mk create mode 100644 vcl/UIConfig_vcl.mk create mode 100644 vcl/WinResTarget_vcl.mk create mode 100644 vcl/android/androidinst.cxx create mode 100644 vcl/backendtest/VisualBackendTest.cxx create mode 100644 vcl/backendtest/outputdevice/bitmap.cxx create mode 100644 vcl/backendtest/outputdevice/clip.cxx create mode 100644 vcl/backendtest/outputdevice/common.cxx create mode 100644 vcl/backendtest/outputdevice/gradient.cxx create mode 100644 vcl/backendtest/outputdevice/line.cxx create mode 100644 vcl/backendtest/outputdevice/outputdevice.cxx create mode 100644 vcl/backendtest/outputdevice/pixel.cxx create mode 100644 vcl/backendtest/outputdevice/polygon.cxx create mode 100644 vcl/backendtest/outputdevice/polyline.cxx create mode 100644 vcl/backendtest/outputdevice/polyline_b2d.cxx create mode 100644 vcl/backendtest/outputdevice/polypolygon.cxx create mode 100644 vcl/backendtest/outputdevice/polypolygon_b2d.cxx create mode 100644 vcl/backendtest/outputdevice/rectangle.cxx create mode 100644 vcl/commonfuzzer.mk create mode 100644 vcl/headless/CustomWidgetDraw.cxx create mode 100644 vcl/headless/headlessinst.cxx create mode 100644 vcl/headless/svpbmp.cxx create mode 100644 vcl/headless/svpcairotextrender.cxx create mode 100644 vcl/headless/svpdata.cxx create mode 100644 vcl/headless/svpdummies.cxx create mode 100644 vcl/headless/svpframe.cxx create mode 100644 vcl/headless/svpgdi.cxx create mode 100644 vcl/headless/svpinst.cxx create mode 100644 vcl/headless/svpprn.cxx create mode 100644 vcl/headless/svptext.cxx create mode 100644 vcl/headless/svpvd.cxx create mode 100644 vcl/inc/BitmapColorizeFilter.hxx create mode 100644 vcl/inc/BitmapDisabledImageFilter.hxx create mode 100644 vcl/inc/BitmapFastScaleFilter.hxx create mode 100644 vcl/inc/BitmapInterpolateScaleFilter.hxx create mode 100644 vcl/inc/BitmapLightenFilter.hxx create mode 100644 vcl/inc/BitmapScaleConvolutionFilter.hxx create mode 100644 vcl/inc/BitmapScaleSuperFilter.hxx create mode 100644 vcl/inc/BitmapSymmetryCheck.hxx create mode 100644 vcl/inc/ControlCacheKey.hxx create mode 100644 vcl/inc/FileDefinitionWidgetDraw.hxx create mode 100644 vcl/inc/IconThemeScanner.hxx create mode 100644 vcl/inc/IconThemeSelector.hxx create mode 100644 vcl/inc/OptionalBox.hxx create mode 100644 vcl/inc/PhysicalFontCollection.hxx create mode 100644 vcl/inc/PhysicalFontFace.hxx create mode 100644 vcl/inc/PhysicalFontFamily.hxx create mode 100644 vcl/inc/ResampleKernel.hxx create mode 100644 vcl/inc/SalGradient.hxx create mode 100644 vcl/inc/TypeSerializer.hxx create mode 100644 vcl/inc/WidgetDrawInterface.hxx create mode 100644 vcl/inc/WidgetThemeLibrary.hxx create mode 100644 vcl/inc/WidgetThemeLibraryTypes.hxx create mode 100644 vcl/inc/accel.h create mode 100644 vcl/inc/accmgr.hxx create mode 100644 vcl/inc/android/androidinst.hxx create mode 100644 vcl/inc/android/svsys.h create mode 100644 vcl/inc/backend/BackendCapabilities.hxx create mode 100644 vcl/inc/bitmap/Octree.hxx create mode 100644 vcl/inc/bitmap/ScanlineTools.hxx create mode 100644 vcl/inc/bitmap/impoctree.hxx create mode 100644 vcl/inc/bitmaps.hlst create mode 100644 vcl/inc/bitmapwriteaccess.hxx create mode 100644 vcl/inc/bmpfast.hxx create mode 100644 vcl/inc/brdwin.hxx create mode 100644 vcl/inc/canvasbitmap.hxx create mode 100644 vcl/inc/configsettings.hxx create mode 100644 vcl/inc/controldata.hxx create mode 100644 vcl/inc/cursor_hotspots.hxx create mode 100644 vcl/inc/dbggui.hxx create mode 100644 vcl/inc/debugevent.hxx create mode 100644 vcl/inc/displayconnectiondispatch.hxx create mode 100644 vcl/inc/dndeventdispatcher.hxx create mode 100644 vcl/inc/dndlistenercontainer.hxx create mode 100644 vcl/inc/driverblocklist.hxx create mode 100644 vcl/inc/factory.hxx create mode 100644 vcl/inc/fltcall.hxx create mode 100644 vcl/inc/font/FeatureCollector.hxx create mode 100644 vcl/inc/font/OpenTypeFeatureDefinitionList.hxx create mode 100644 vcl/inc/font/OpenTypeFeatureStrings.hrc create mode 100644 vcl/inc/fontattributes.hxx create mode 100644 vcl/inc/fontinstance.hxx create mode 100644 vcl/inc/fontselect.hxx create mode 100644 vcl/inc/fontsubset.hxx create mode 100644 vcl/inc/graphic/DetectorTools.hxx create mode 100644 vcl/inc/graphic/GraphicFormatDetector.hxx create mode 100644 vcl/inc/graphic/GraphicID.hxx create mode 100644 vcl/inc/graphic/GraphicReader.hxx create mode 100644 vcl/inc/graphic/Manager.hxx create mode 100644 vcl/inc/graphic/UnoGraphic.hxx create mode 100644 vcl/inc/graphic/UnoGraphicDescriptor.hxx create mode 100644 vcl/inc/graphic/UnoGraphicTransformer.hxx create mode 100644 vcl/inc/headless/CustomWidgetDraw.hxx create mode 100644 vcl/inc/headless/svpbmp.hxx create mode 100644 vcl/inc/headless/svpcairotextrender.hxx create mode 100644 vcl/inc/headless/svpdummies.hxx create mode 100644 vcl/inc/headless/svpframe.hxx create mode 100644 vcl/inc/headless/svpgdi.hxx create mode 100644 vcl/inc/headless/svpinst.hxx create mode 100644 vcl/inc/headless/svpprn.hxx create mode 100644 vcl/inc/headless/svpvd.hxx create mode 100644 vcl/inc/helpwin.hxx create mode 100644 vcl/inc/hyperlabel.hxx create mode 100644 vcl/inc/iconview.hxx create mode 100644 vcl/inc/image.h create mode 100644 vcl/inc/imagerepository.hxx create mode 100644 vcl/inc/impanmvw.hxx create mode 100644 vcl/inc/impdel.hxx create mode 100644 vcl/inc/impfont.hxx create mode 100644 vcl/inc/impfontcache.hxx create mode 100644 vcl/inc/impfontcharmap.hxx create mode 100644 vcl/inc/impfontmetricdata.hxx create mode 100644 vcl/inc/impglyphitem.hxx create mode 100644 vcl/inc/impgraph.hxx create mode 100644 vcl/inc/implimagetree.hxx create mode 100644 vcl/inc/ios/iosinst.hxx create mode 100644 vcl/inc/ios/svsys.h create mode 100644 vcl/inc/jobdata.hxx create mode 100644 vcl/inc/jobset.h create mode 100644 vcl/inc/jsdialog/jsdialogbuilder.hxx create mode 100644 vcl/inc/langboost.hxx create mode 100644 vcl/inc/listbox.hxx create mode 100644 vcl/inc/messagedialog.hxx create mode 100644 vcl/inc/opengl/BufferObject.hxx create mode 100644 vcl/inc/opengl/DeviceInfo.hxx create mode 100644 vcl/inc/opengl/FixedTextureAtlas.hxx create mode 100644 vcl/inc/opengl/LineRenderUtils.hxx create mode 100644 vcl/inc/opengl/PackedTextureAtlas.hxx create mode 100644 vcl/inc/opengl/RenderList.hxx create mode 100644 vcl/inc/opengl/RenderState.hxx create mode 100644 vcl/inc/opengl/TextureState.hxx create mode 100644 vcl/inc/opengl/VertexUtils.hxx create mode 100644 vcl/inc/opengl/framebuffer.hxx create mode 100644 vcl/inc/opengl/gdiimpl.hxx create mode 100644 vcl/inc/opengl/program.hxx create mode 100644 vcl/inc/opengl/salbmp.hxx create mode 100644 vcl/inc/opengl/texture.hxx create mode 100644 vcl/inc/opengl/win/WinDeviceInfo.hxx create mode 100644 vcl/inc/opengl/win/gdiimpl.hxx create mode 100644 vcl/inc/opengl/win/winlayout.hxx create mode 100644 vcl/inc/opengl/x11/X11DeviceInfo.hxx create mode 100644 vcl/inc/opengl/x11/cairotextrender.hxx create mode 100644 vcl/inc/opengl/x11/gdiimpl.hxx create mode 100644 vcl/inc/opengl/x11/glxtest.hxx create mode 100644 vcl/inc/opengl/x11/salvd.hxx create mode 100644 vcl/inc/opengl/zone.hxx create mode 100644 vcl/inc/osx/a11yfactory.h create mode 100644 vcl/inc/osx/a11yfocustracker.hxx create mode 100644 vcl/inc/osx/a11ylistener.hxx create mode 100644 vcl/inc/osx/a11ywrapper.h create mode 100644 vcl/inc/osx/keyboardfocuslistener.hxx create mode 100644 vcl/inc/osx/osxvcltypes.h create mode 100644 vcl/inc/osx/printview.h create mode 100644 vcl/inc/osx/runinmain.hxx create mode 100644 vcl/inc/osx/saldata.hxx create mode 100644 vcl/inc/osx/salframe.h create mode 100644 vcl/inc/osx/salframeview.h create mode 100644 vcl/inc/osx/salinst.h create mode 100644 vcl/inc/osx/salmenu.h create mode 100644 vcl/inc/osx/salnativewidgets.h create mode 100644 vcl/inc/osx/salnsmenu.h create mode 100644 vcl/inc/osx/salnstimer.h create mode 100644 vcl/inc/osx/salobj.h create mode 100644 vcl/inc/osx/salprn.h create mode 100644 vcl/inc/osx/salsys.h create mode 100644 vcl/inc/osx/saltimer.h create mode 100644 vcl/inc/osx/svsys.h create mode 100644 vcl/inc/osx/vclnsapp.h create mode 100644 vcl/inc/outdata.hxx create mode 100644 vcl/inc/outdev.h create mode 100644 vcl/inc/pch/precompiled_vcl.cxx create mode 100644 vcl/inc/pch/precompiled_vcl.hxx create mode 100644 vcl/inc/pdf/BitmapID.hxx create mode 100644 vcl/inc/pdf/Matrix3.hxx create mode 100644 vcl/inc/pdf/ResourceDict.hxx create mode 100644 vcl/inc/pdf/XmpMetadata.hxx create mode 100644 vcl/inc/ppdparser.hxx create mode 100644 vcl/inc/print.h create mode 100644 vcl/inc/print.hrc create mode 100644 vcl/inc/printaccessoryview.hrc create mode 100644 vcl/inc/printdlg.hxx create mode 100644 vcl/inc/printerinfomanager.hxx create mode 100644 vcl/inc/qt5/Qt5AccessibleEventListener.hxx create mode 100644 vcl/inc/qt5/Qt5AccessibleWidget.hxx create mode 100644 vcl/inc/qt5/Qt5Bitmap.hxx create mode 100644 vcl/inc/qt5/Qt5Clipboard.hxx create mode 100644 vcl/inc/qt5/Qt5Data.hxx create mode 100644 vcl/inc/qt5/Qt5DragAndDrop.hxx create mode 100644 vcl/inc/qt5/Qt5FilePicker.hxx create mode 100644 vcl/inc/qt5/Qt5Font.hxx create mode 100644 vcl/inc/qt5/Qt5FontFace.hxx create mode 100644 vcl/inc/qt5/Qt5Frame.hxx create mode 100644 vcl/inc/qt5/Qt5Graphics.hxx create mode 100644 vcl/inc/qt5/Qt5GraphicsBase.hxx create mode 100644 vcl/inc/qt5/Qt5Graphics_Controls.hxx create mode 100644 vcl/inc/qt5/Qt5Instance.hxx create mode 100644 vcl/inc/qt5/Qt5MainWindow.hxx create mode 100644 vcl/inc/qt5/Qt5Menu.hxx create mode 100644 vcl/inc/qt5/Qt5Object.hxx create mode 100644 vcl/inc/qt5/Qt5OpenGLContext.hxx create mode 100644 vcl/inc/qt5/Qt5Painter.hxx create mode 100644 vcl/inc/qt5/Qt5Printer.hxx create mode 100644 vcl/inc/qt5/Qt5SvpGraphics.hxx create mode 100644 vcl/inc/qt5/Qt5SvpSurface.hxx create mode 100644 vcl/inc/qt5/Qt5System.hxx create mode 100644 vcl/inc/qt5/Qt5Timer.hxx create mode 100644 vcl/inc/qt5/Qt5Tools.hxx create mode 100644 vcl/inc/qt5/Qt5Transferable.hxx create mode 100644 vcl/inc/qt5/Qt5VirtualDevice.hxx create mode 100644 vcl/inc/qt5/Qt5Widget.hxx create mode 100644 vcl/inc/qt5/Qt5XAccessible.hxx create mode 100644 vcl/inc/quartz/CGHelpers.hxx create mode 100644 vcl/inc/quartz/common.h create mode 100644 vcl/inc/quartz/ctfonts.hxx create mode 100644 vcl/inc/quartz/salbmp.h create mode 100644 vcl/inc/quartz/salgdi.h create mode 100644 vcl/inc/quartz/salgdicommon.hxx create mode 100644 vcl/inc/quartz/salvd.h create mode 100644 vcl/inc/quartz/utils.h create mode 100644 vcl/inc/regband.hxx create mode 100644 vcl/inc/regionband.hxx create mode 100644 vcl/inc/salbmp.hxx create mode 100644 vcl/inc/saldatabasic.hxx create mode 100644 vcl/inc/salframe.hxx create mode 100644 vcl/inc/salgdi.hxx create mode 100644 vcl/inc/salgdiimpl.hxx create mode 100644 vcl/inc/salgeom.hxx create mode 100644 vcl/inc/salinst.hxx create mode 100644 vcl/inc/sallayout.hxx create mode 100644 vcl/inc/salmenu.hxx create mode 100644 vcl/inc/salobj.hxx create mode 100644 vcl/inc/salprn.hxx create mode 100644 vcl/inc/salptype.hxx create mode 100644 vcl/inc/salsession.hxx create mode 100644 vcl/inc/salsys.hxx create mode 100644 vcl/inc/saltimer.hxx create mode 100644 vcl/inc/salusereventlist.hxx create mode 100644 vcl/inc/salvd.hxx create mode 100644 vcl/inc/salvtables.hxx create mode 100644 vcl/inc/salwtype.hxx create mode 100644 vcl/inc/scanlinewriter.hxx create mode 100644 vcl/inc/schedulerimpl.hxx create mode 100644 vcl/inc/scrptrun.h create mode 100644 vcl/inc/scrwnd.hxx create mode 100644 vcl/inc/sft.hxx create mode 100644 vcl/inc/skia/gdiimpl.hxx create mode 100644 vcl/inc/skia/salbmp.hxx create mode 100644 vcl/inc/skia/utils.hxx create mode 100644 vcl/inc/skia/win/gdiimpl.hxx create mode 100644 vcl/inc/skia/x11/gdiimpl.hxx create mode 100644 vcl/inc/skia/x11/salvd.hxx create mode 100644 vcl/inc/skia/x11/textrender.hxx create mode 100644 vcl/inc/skia/zone.hxx create mode 100644 vcl/inc/slider.hxx create mode 100644 vcl/inc/spin.hxx create mode 100644 vcl/inc/strhelper.hxx create mode 100644 vcl/inc/strings.hrc create mode 100644 vcl/inc/strings.hxx create mode 100644 vcl/inc/svdata.hxx create mode 100644 vcl/inc/svimpbox.hxx create mode 100644 vcl/inc/svmconverter.hxx create mode 100644 vcl/inc/svsys.h create mode 100644 vcl/inc/test/outputdevice.hxx create mode 100644 vcl/inc/textlayout.hxx create mode 100644 vcl/inc/textlineinfo.hxx create mode 100644 vcl/inc/textrender.hxx create mode 100644 vcl/inc/toolbox.h create mode 100644 vcl/inc/treeglue.hxx create mode 100644 vcl/inc/uiobject-internal.hxx create mode 100644 vcl/inc/units.hrc create mode 100644 vcl/inc/unx/XIM.h create mode 100644 vcl/inc/unx/cairotextrender.hxx create mode 100644 vcl/inc/unx/cpdmgr.hxx create mode 100644 vcl/inc/unx/cupsmgr.hxx create mode 100644 vcl/inc/unx/desktops.hxx create mode 100644 vcl/inc/unx/fc_fontoptions.hxx create mode 100644 vcl/inc/unx/fontmanager.hxx create mode 100644 vcl/inc/unx/freetype_glyphcache.hxx create mode 100644 vcl/inc/unx/freetypetextrender.hxx create mode 100644 vcl/inc/unx/gendata.hxx create mode 100644 vcl/inc/unx/gendisp.hxx create mode 100644 vcl/inc/unx/geninst.h create mode 100644 vcl/inc/unx/genprn.h create mode 100644 vcl/inc/unx/genpspgraphics.h create mode 100644 vcl/inc/unx/gensys.h create mode 100644 vcl/inc/unx/glyphcache.hxx create mode 100644 vcl/inc/unx/gstsink.hxx create mode 100644 vcl/inc/unx/gtk/atkbridge.hxx create mode 100644 vcl/inc/unx/gtk/gloactiongroup.h create mode 100644 vcl/inc/unx/gtk/glomenu.h create mode 100644 vcl/inc/unx/gtk/gtkbackend.hxx create mode 100644 vcl/inc/unx/gtk/gtkdata.hxx create mode 100644 vcl/inc/unx/gtk/gtkframe.hxx create mode 100644 vcl/inc/unx/gtk/gtkgdi.hxx create mode 100644 vcl/inc/unx/gtk/gtkinst.hxx create mode 100644 vcl/inc/unx/gtk/gtkobject.hxx create mode 100644 vcl/inc/unx/gtk/gtkprintwrapper.hxx create mode 100644 vcl/inc/unx/gtk/gtkprn.hxx create mode 100644 vcl/inc/unx/gtk/gtksalmenu.hxx create mode 100644 vcl/inc/unx/gtk/gtksys.hxx create mode 100644 vcl/inc/unx/gtk/hudawareness.h create mode 100644 vcl/inc/unx/helper.hxx create mode 100644 vcl/inc/unx/i18n_cb.hxx create mode 100644 vcl/inc/unx/i18n_ic.hxx create mode 100644 vcl/inc/unx/i18n_im.hxx create mode 100644 vcl/inc/unx/i18n_keysym.hxx create mode 100644 vcl/inc/unx/i18n_xkb.hxx create mode 100644 vcl/inc/unx/nativewindowhandleprovider.hxx create mode 100644 vcl/inc/unx/printergfx.hxx create mode 100644 vcl/inc/unx/printerjob.hxx create mode 100644 vcl/inc/unx/salbmp.h create mode 100644 vcl/inc/unx/saldata.hxx create mode 100644 vcl/inc/unx/saldisp.hxx create mode 100644 vcl/inc/unx/salframe.h create mode 100644 vcl/inc/unx/salgdi.h create mode 100644 vcl/inc/unx/salinst.h create mode 100644 vcl/inc/unx/salobj.h create mode 100644 vcl/inc/unx/saltimer.h create mode 100644 vcl/inc/unx/saltype.h create mode 100644 vcl/inc/unx/salunx.h create mode 100644 vcl/inc/unx/salunxtime.h create mode 100644 vcl/inc/unx/salvd.h create mode 100644 vcl/inc/unx/screensaverinhibitor.hxx create mode 100644 vcl/inc/unx/sm.hxx create mode 100644 vcl/inc/unx/svsys.h create mode 100644 vcl/inc/unx/wmadaptor.hxx create mode 100644 vcl/inc/unx/x11/x11cairotextrender.hxx create mode 100644 vcl/inc/unx/x11/x11gdiimpl.h create mode 100644 vcl/inc/unx/x11/x11sys.hxx create mode 100644 vcl/inc/unx/x11/xlimits.hxx create mode 100644 vcl/inc/unx/x11/xrender_peer.hxx create mode 100644 vcl/inc/unx/x11_cursors/ase_curs.h create mode 100644 vcl/inc/unx/x11_cursors/ase_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asn_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asn_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asne_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asne_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asns_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asns_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asnswe_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asnswe_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asnw_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asnw_mask.h create mode 100644 vcl/inc/unx/x11_cursors/ass_curs.h create mode 100644 vcl/inc/unx/x11_cursors/ass_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asse_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asse_mask.h create mode 100644 vcl/inc/unx/x11_cursors/assw_curs.h create mode 100644 vcl/inc/unx/x11_cursors/assw_mask.h create mode 100644 vcl/inc/unx/x11_cursors/asw_curs.h create mode 100644 vcl/inc/unx/x11_cursors/asw_mask.h create mode 100644 vcl/inc/unx/x11_cursors/aswe_curs.h create mode 100644 vcl/inc/unx/x11_cursors/aswe_mask.h create mode 100644 vcl/inc/unx/x11_cursors/chain_curs.h create mode 100644 vcl/inc/unx/x11_cursors/chain_mask.h create mode 100644 vcl/inc/unx/x11_cursors/chainnot_curs.h create mode 100644 vcl/inc/unx/x11_cursors/chainnot_mask.h create mode 100644 vcl/inc/unx/x11_cursors/chart_curs.h create mode 100644 vcl/inc/unx/x11_cursors/chart_mask.h create mode 100644 vcl/inc/unx/x11_cursors/copydata_curs.h create mode 100644 vcl/inc/unx/x11_cursors/copydata_mask.h create mode 100644 vcl/inc/unx/x11_cursors/copydlnk_curs.h create mode 100644 vcl/inc/unx/x11_cursors/copydlnk_mask.h create mode 100644 vcl/inc/unx/x11_cursors/copyfile_curs.h create mode 100644 vcl/inc/unx/x11_cursors/copyfile_mask.h create mode 100644 vcl/inc/unx/x11_cursors/copyfiles_curs.h create mode 100644 vcl/inc/unx/x11_cursors/copyfiles_mask.h create mode 100644 vcl/inc/unx/x11_cursors/copyflnk_curs.h create mode 100644 vcl/inc/unx/x11_cursors/copyflnk_mask.h create mode 100644 vcl/inc/unx/x11_cursors/crook_curs.h create mode 100644 vcl/inc/unx/x11_cursors/crook_mask.h create mode 100644 vcl/inc/unx/x11_cursors/crop_curs.h create mode 100644 vcl/inc/unx/x11_cursors/crop_mask.h create mode 100644 vcl/inc/unx/x11_cursors/detective_curs.h create mode 100644 vcl/inc/unx/x11_cursors/detective_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawarc_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawarc_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawbezier_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawbezier_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawcaption_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawcaption_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawcirclecut_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawcirclecut_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawconnect_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawconnect_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawellipse_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawellipse_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawfreehand_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawfreehand_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawline_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawline_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawpie_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawpie_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawpolygon_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawpolygon_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawrect_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawrect_mask.h create mode 100644 vcl/inc/unx/x11_cursors/drawtext_curs.h create mode 100644 vcl/inc/unx/x11_cursors/drawtext_mask.h create mode 100644 vcl/inc/unx/x11_cursors/fill_curs.h create mode 100644 vcl/inc/unx/x11_cursors/fill_mask.h create mode 100644 vcl/inc/unx/x11_cursors/hshear_curs.h create mode 100644 vcl/inc/unx/x11_cursors/hshear_mask.h create mode 100644 vcl/inc/unx/x11_cursors/invert50.h create mode 100644 vcl/inc/unx/x11_cursors/linkdata_curs.h create mode 100644 vcl/inc/unx/x11_cursors/linkdata_mask.h create mode 100644 vcl/inc/unx/x11_cursors/linkfile_curs.h create mode 100644 vcl/inc/unx/x11_cursors/linkfile_mask.h create mode 100644 vcl/inc/unx/x11_cursors/magnify_curs.h create mode 100644 vcl/inc/unx/x11_cursors/magnify_mask.h create mode 100644 vcl/inc/unx/x11_cursors/mirror_curs.h create mode 100644 vcl/inc/unx/x11_cursors/mirror_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movebezierweight_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movebezierweight_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movedata_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movedata_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movedlnk_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movedlnk_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movefile_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movefile_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movefiles_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movefiles_mask.h create mode 100644 vcl/inc/unx/x11_cursors/moveflnk_curs.h create mode 100644 vcl/inc/unx/x11_cursors/moveflnk_mask.h create mode 100644 vcl/inc/unx/x11_cursors/movepoint_curs.h create mode 100644 vcl/inc/unx/x11_cursors/movepoint_mask.h create mode 100644 vcl/inc/unx/x11_cursors/nodrop_curs.h create mode 100644 vcl/inc/unx/x11_cursors/nodrop_mask.h create mode 100644 vcl/inc/unx/x11_cursors/null_curs.h create mode 100644 vcl/inc/unx/x11_cursors/null_mask.h create mode 100644 vcl/inc/unx/x11_cursors/pivotcol_curs.h create mode 100644 vcl/inc/unx/x11_cursors/pivotcol_mask.h create mode 100644 vcl/inc/unx/x11_cursors/pivotdel_curs.h create mode 100644 vcl/inc/unx/x11_cursors/pivotdel_mask.h create mode 100644 vcl/inc/unx/x11_cursors/pivotfld_curs.h create mode 100644 vcl/inc/unx/x11_cursors/pivotfld_mask.h create mode 100644 vcl/inc/unx/x11_cursors/pivotrow_curs.h create mode 100644 vcl/inc/unx/x11_cursors/pivotrow_mask.h create mode 100644 vcl/inc/unx/x11_cursors/rotate_curs.h create mode 100644 vcl/inc/unx/x11_cursors/rotate_mask.h create mode 100644 vcl/inc/unx/x11_cursors/salcursors.h create mode 100644 vcl/inc/unx/x11_cursors/tblsele_curs.h create mode 100644 vcl/inc/unx/x11_cursors/tblsele_mask.h create mode 100644 vcl/inc/unx/x11_cursors/tblsels_curs.h create mode 100644 vcl/inc/unx/x11_cursors/tblsels_mask.h create mode 100644 vcl/inc/unx/x11_cursors/tblselse_curs.h create mode 100644 vcl/inc/unx/x11_cursors/tblselse_mask.h create mode 100644 vcl/inc/unx/x11_cursors/tblselsw_curs.h create mode 100644 vcl/inc/unx/x11_cursors/tblselsw_mask.h create mode 100644 vcl/inc/unx/x11_cursors/tblselw_curs.h create mode 100644 vcl/inc/unx/x11_cursors/tblselw_mask.h create mode 100644 vcl/inc/unx/x11_cursors/vertcurs_curs.h create mode 100644 vcl/inc/unx/x11_cursors/vertcurs_mask.h create mode 100644 vcl/inc/unx/x11_cursors/vshear_curs.h create mode 100644 vcl/inc/unx/x11_cursors/vshear_mask.h create mode 100644 vcl/inc/unx/x11_cursors/wshide_curs.h create mode 100644 vcl/inc/unx/x11_cursors/wshide_mask.h create mode 100644 vcl/inc/unx/x11_cursors/wsshow_curs.h create mode 100644 vcl/inc/unx/x11_cursors/wsshow_mask.h create mode 100644 vcl/inc/vcleventlisteners.hxx create mode 100644 vcl/inc/vclpluginapi.h create mode 100644 vcl/inc/vclstatuslistener.hxx create mode 100644 vcl/inc/wall2.hxx create mode 100644 vcl/inc/watchdog.hxx create mode 100644 vcl/inc/widgetdraw/WidgetDefinition.hxx create mode 100644 vcl/inc/widgetdraw/WidgetDefinitionReader.hxx create mode 100644 vcl/inc/win/DWriteTextRenderer.hxx create mode 100644 vcl/inc/win/salbmp.h create mode 100644 vcl/inc/win/saldata.hxx create mode 100644 vcl/inc/win/salframe.h create mode 100644 vcl/inc/win/salgdi.h create mode 100644 vcl/inc/win/salids.hrc create mode 100644 vcl/inc/win/salinst.h create mode 100644 vcl/inc/win/salmenu.h create mode 100644 vcl/inc/win/salobj.h create mode 100644 vcl/inc/win/salprn.h create mode 100644 vcl/inc/win/salsys.h create mode 100644 vcl/inc/win/saltimer.h create mode 100644 vcl/inc/win/salvd.h create mode 100644 vcl/inc/win/scoped_gdi.hxx create mode 100644 vcl/inc/win/svsys.h create mode 100644 vcl/inc/win/wincomp.hxx create mode 100644 vcl/inc/win/wingdiimpl.hxx create mode 100644 vcl/inc/win/winlayout.hxx create mode 100644 vcl/inc/window.h create mode 100644 vcl/inc/wizdlg.hxx create mode 100644 vcl/ios/DataFlavorMapping.cxx create mode 100644 vcl/ios/DataFlavorMapping.hxx create mode 100644 vcl/ios/HtmlFmtFlt.cxx create mode 100644 vcl/ios/HtmlFmtFlt.hxx create mode 100644 vcl/ios/clipboard.cxx create mode 100644 vcl/ios/clipboard.hxx create mode 100644 vcl/ios/dummies.cxx create mode 100644 vcl/ios/iOSTransferable.cxx create mode 100644 vcl/ios/iOSTransferable.hxx create mode 100644 vcl/ios/iosinst.cxx create mode 100644 vcl/jsdialog/jsdialogbuilder.cxx create mode 100644 vcl/null/printerinfomanager.cxx create mode 100644 vcl/opengl/DeviceInfo.cxx create mode 100644 vcl/opengl/FixedTextureAtlas.cxx create mode 100644 vcl/opengl/LineRenderUtils.cxx create mode 100644 vcl/opengl/PackedTextureAtlas.cxx create mode 100644 vcl/opengl/README.deprecated create mode 100644 vcl/opengl/README.opengl create mode 100644 vcl/opengl/RenderList.cxx create mode 100644 vcl/opengl/framebuffer.cxx create mode 100644 vcl/opengl/gdiimpl.cxx create mode 100644 vcl/opengl/opengl_blacklist_windows.xml create mode 100644 vcl/opengl/program.cxx create mode 100644 vcl/opengl/salbmp.cxx create mode 100644 vcl/opengl/scale.cxx create mode 100644 vcl/opengl/shaders/areaHashCRC64TFragmentShader.glsl create mode 100644 vcl/opengl/shaders/areaScaleFastFragmentShader.glsl create mode 100644 vcl/opengl/shaders/areaScaleFragmentShader.glsl create mode 100644 vcl/opengl/shaders/blendedTextureFragmentShader.glsl create mode 100644 vcl/opengl/shaders/blendedTextureVertexShader.glsl create mode 100644 vcl/opengl/shaders/combinedFragmentShader.glsl create mode 100644 vcl/opengl/shaders/combinedTextureFragmentShader.glsl create mode 100644 vcl/opengl/shaders/combinedTextureVertexShader.glsl create mode 100644 vcl/opengl/shaders/combinedVertexShader.glsl create mode 100644 vcl/opengl/shaders/convolutionFragmentShader.glsl create mode 100644 vcl/opengl/shaders/diffTextureFragmentShader.glsl create mode 100644 vcl/opengl/shaders/dumbVertexShader.glsl create mode 100644 vcl/opengl/shaders/greyscaleFragmentShader.glsl create mode 100644 vcl/opengl/shaders/invert50FragmentShader.glsl create mode 100644 vcl/opengl/shaders/lineFragmentShader.glsl create mode 100644 vcl/opengl/shaders/lineVertexShader.glsl create mode 100644 vcl/opengl/shaders/linearGradientFragmentShader.glsl create mode 100644 vcl/opengl/shaders/maskFragmentShader.glsl create mode 100644 vcl/opengl/shaders/maskedTextureFragmentShader.glsl create mode 100644 vcl/opengl/shaders/maskedTextureVertexShader.glsl create mode 100644 vcl/opengl/shaders/radialGradientFragmentShader.glsl create mode 100644 vcl/opengl/shaders/replaceColorFragmentShader.glsl create mode 100644 vcl/opengl/shaders/solidFragmentShader.glsl create mode 100644 vcl/opengl/shaders/textureFragmentShader.glsl create mode 100644 vcl/opengl/shaders/textureVertexShader.glsl create mode 100644 vcl/opengl/shaders/transformedTextureVertexShader.glsl create mode 100644 vcl/opengl/texture.cxx create mode 100644 vcl/opengl/win/WinDeviceInfo.cxx create mode 100644 vcl/opengl/win/gdiimpl.cxx create mode 100644 vcl/opengl/win/winlayout.cxx create mode 100644 vcl/opengl/x11/X11DeviceInfo.cxx create mode 100644 vcl/opengl/x11/cairotextrender.cxx create mode 100644 vcl/opengl/x11/gdiimpl.cxx create mode 100644 vcl/opengl/x11/salvd.cxx create mode 100644 vcl/osx/DataFlavorMapping.cxx create mode 100644 vcl/osx/DataFlavorMapping.hxx create mode 100644 vcl/osx/DragActionConversion.cxx create mode 100644 vcl/osx/DragActionConversion.hxx create mode 100644 vcl/osx/DragSource.cxx create mode 100644 vcl/osx/DragSource.hxx create mode 100644 vcl/osx/DragSourceContext.cxx create mode 100644 vcl/osx/DragSourceContext.hxx create mode 100644 vcl/osx/DropTarget.cxx create mode 100644 vcl/osx/DropTarget.hxx create mode 100644 vcl/osx/HtmlFmtFlt.cxx create mode 100644 vcl/osx/HtmlFmtFlt.hxx create mode 100644 vcl/osx/OSXTransferable.cxx create mode 100644 vcl/osx/OSXTransferable.hxx create mode 100644 vcl/osx/PictToBmpFlt.cxx create mode 100644 vcl/osx/PictToBmpFlt.hxx create mode 100644 vcl/osx/README.a11y create mode 100644 vcl/osx/a11yactionwrapper.h create mode 100644 vcl/osx/a11yactionwrapper.mm create mode 100644 vcl/osx/a11ycomponentwrapper.h create mode 100644 vcl/osx/a11ycomponentwrapper.mm create mode 100644 vcl/osx/a11yfactory.mm create mode 100644 vcl/osx/a11yfocuslistener.cxx create mode 100644 vcl/osx/a11yfocuslistener.hxx create mode 100644 vcl/osx/a11yfocustracker.cxx create mode 100644 vcl/osx/a11ylistener.cxx create mode 100644 vcl/osx/a11yrolehelper.h create mode 100644 vcl/osx/a11yrolehelper.mm create mode 100644 vcl/osx/a11yselectionwrapper.h create mode 100644 vcl/osx/a11yselectionwrapper.mm create mode 100644 vcl/osx/a11ytablewrapper.h create mode 100644 vcl/osx/a11ytablewrapper.mm create mode 100644 vcl/osx/a11ytextattributeswrapper.h create mode 100644 vcl/osx/a11ytextattributeswrapper.mm create mode 100644 vcl/osx/a11ytextwrapper.h create mode 100644 vcl/osx/a11ytextwrapper.mm create mode 100644 vcl/osx/a11yutil.h create mode 100644 vcl/osx/a11yutil.mm create mode 100644 vcl/osx/a11yvaluewrapper.h create mode 100644 vcl/osx/a11yvaluewrapper.mm create mode 100644 vcl/osx/a11ywrapper.mm create mode 100644 vcl/osx/a11ywrapperbutton.h create mode 100644 vcl/osx/a11ywrapperbutton.mm create mode 100644 vcl/osx/a11ywrappercheckbox.h create mode 100644 vcl/osx/a11ywrappercheckbox.mm create mode 100644 vcl/osx/a11ywrappercombobox.h create mode 100644 vcl/osx/a11ywrappercombobox.mm create mode 100644 vcl/osx/a11ywrappergroup.h create mode 100644 vcl/osx/a11ywrappergroup.mm create mode 100644 vcl/osx/a11ywrapperlist.h create mode 100644 vcl/osx/a11ywrapperlist.mm create mode 100644 vcl/osx/a11ywrapperradiobutton.h create mode 100644 vcl/osx/a11ywrapperradiobutton.mm create mode 100644 vcl/osx/a11ywrapperradiogroup.h create mode 100644 vcl/osx/a11ywrapperradiogroup.mm create mode 100644 vcl/osx/a11ywrapperrow.h create mode 100644 vcl/osx/a11ywrapperrow.mm create mode 100644 vcl/osx/a11ywrapperscrollarea.h create mode 100644 vcl/osx/a11ywrapperscrollarea.mm create mode 100644 vcl/osx/a11ywrapperscrollbar.h create mode 100644 vcl/osx/a11ywrapperscrollbar.mm create mode 100644 vcl/osx/a11ywrappersplitter.h create mode 100644 vcl/osx/a11ywrappersplitter.mm create mode 100644 vcl/osx/a11ywrapperstatictext.h create mode 100644 vcl/osx/a11ywrapperstatictext.mm create mode 100644 vcl/osx/a11ywrappertabgroup.h create mode 100644 vcl/osx/a11ywrappertabgroup.mm create mode 100644 vcl/osx/a11ywrappertextarea.h create mode 100644 vcl/osx/a11ywrappertextarea.mm create mode 100644 vcl/osx/a11ywrappertoolbar.h create mode 100644 vcl/osx/a11ywrappertoolbar.mm create mode 100644 vcl/osx/clipboard.cxx create mode 100644 vcl/osx/clipboard.hxx create mode 100644 vcl/osx/cuidraw.hxx create mode 100644 vcl/osx/documentfocuslistener.cxx create mode 100644 vcl/osx/documentfocuslistener.hxx create mode 100644 vcl/osx/printaccessoryview.mm create mode 100644 vcl/osx/printview.mm create mode 100644 vcl/osx/res/MainMenu.nib/classes.nib create mode 100644 vcl/osx/res/MainMenu.nib/info.nib create mode 100644 vcl/osx/res/MainMenu.nib/keyedobjects.nib create mode 100644 vcl/osx/saldata.cxx create mode 100644 vcl/osx/salframe.cxx create mode 100644 vcl/osx/salframeview.mm create mode 100644 vcl/osx/salinst.cxx create mode 100644 vcl/osx/salmenu.cxx create mode 100644 vcl/osx/salnativewidgets.cxx create mode 100644 vcl/osx/salnsmenu.mm create mode 100644 vcl/osx/salnstimer.mm create mode 100644 vcl/osx/salobj.cxx create mode 100644 vcl/osx/salprn.cxx create mode 100644 vcl/osx/salsys.cxx create mode 100644 vcl/osx/saltimer.cxx create mode 100644 vcl/osx/service_entry.cxx create mode 100644 vcl/osx/vclnsapp.mm create mode 100644 vcl/qa/afl-eventtesting/README.eventtesting create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress.crash-1 create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress.crash-2 create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress.crash-3 create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress.crash-4 create mode 100644 vcl/qa/afl-eventtesting/eventtesting.impress.crash-5 create mode 100644 vcl/qa/afl-eventtesting/eventtesting.writer create mode 100644 vcl/qa/api/XGraphicTest.cxx create mode 100644 vcl/qa/api/data/TestGraphic.png create mode 100644 vcl/qa/cppunit/BackendTest.cxx create mode 100644 vcl/qa/cppunit/BitmapExTest.cxx create mode 100644 vcl/qa/cppunit/BitmapFilterTest.cxx create mode 100644 vcl/qa/cppunit/BitmapProcessorTest.cxx create mode 100644 vcl/qa/cppunit/BitmapScaleTest.cxx create mode 100644 vcl/qa/cppunit/BitmapTest.cxx create mode 100644 vcl/qa/cppunit/FontFeatureTest.cxx create mode 100644 vcl/qa/cppunit/GraphicDescriptorTest.cxx create mode 100644 vcl/qa/cppunit/GraphicFormatDetectorTest.cxx create mode 100644 vcl/qa/cppunit/GraphicNativeMetadataTest.cxx create mode 100644 vcl/qa/cppunit/GraphicTest.cxx create mode 100644 vcl/qa/cppunit/ScanlineToolsTest.cxx create mode 100644 vcl/qa/cppunit/TypeSerializerTest.cxx create mode 100644 vcl/qa/cppunit/app/test_IconThemeInfo.cxx create mode 100644 vcl/qa/cppunit/app/test_IconThemeScanner.cxx create mode 100644 vcl/qa/cppunit/app/test_IconThemeSelector.cxx create mode 100644 vcl/qa/cppunit/bitmapcolor.cxx create mode 100644 vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx create mode 100644 vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png create mode 100644 vcl/qa/cppunit/bitmaprender/data/tdf104141.gif create mode 100644 vcl/qa/cppunit/bitmaprender/data/tdf113918.png create mode 100644 vcl/qa/cppunit/bitmaprender/data/tdf116888.gif create mode 100644 vcl/qa/cppunit/blocklistparsertest.cxx create mode 100644 vcl/qa/cppunit/builder/demo.ui create mode 100644 vcl/qa/cppunit/canvasbitmaptest.cxx create mode 100644 vcl/qa/cppunit/complextext.cxx create mode 100644 vcl/qa/cppunit/data/123_Numbers.gif create mode 100644 vcl/qa/cppunit/data/Exif1.jpg create mode 100644 vcl/qa/cppunit/data/Exif1_090CW.jpg create mode 100644 vcl/qa/cppunit/data/Exif1_180.jpg create mode 100644 vcl/qa/cppunit/data/Exif1_270CW.jpg create mode 100644 vcl/qa/cppunit/data/SimpleExample.svg create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.bmp create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.eps create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.gif create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.jpg create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.met create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.pcx create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.pdf create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.png create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.psd create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.svg create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.svgz create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.tga create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.tif create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.wmf create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.xbm create mode 100644 vcl/qa/cppunit/data/TypeDetectionExample.xpm create mode 100644 vcl/qa/cppunit/data/inch-size.emf create mode 100644 vcl/qa/cppunit/data/testBasicMorphology.png create mode 100644 vcl/qa/cppunit/data/testBasicMorphologyDilated1.png create mode 100644 vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png create mode 100644 vcl/qa/cppunit/data/testBasicMorphologyDilated2.png create mode 100644 vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png create mode 100644 vcl/qa/cppunit/dndtest.cxx create mode 100644 vcl/qa/cppunit/errorhandler.cxx create mode 100644 vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf create mode 100644 vcl/qa/cppunit/filter/ipdf/ipdf.cxx create mode 100644 vcl/qa/cppunit/font.cxx create mode 100644 vcl/qa/cppunit/fontcharmap.cxx create mode 100644 vcl/qa/cppunit/fontmetric.cxx create mode 100644 vcl/qa/cppunit/gen/data/tdf121120.png create mode 100644 vcl/qa/cppunit/gen/gen.cxx create mode 100644 vcl/qa/cppunit/graphicfilter/data/README create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0951-2.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2016-0952-2.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/EDB-34720-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/fail/afl-sample-Z_NEED_DICT.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0951-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/CVE-2016-0952-1.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/afl-sample-IDAT.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/black.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/png/pass/invalid-chunk.png create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-1.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-2.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-3.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-4.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-5.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/mapmode-6.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/fail/ofz7165-1.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/svm/pass/leak-1.svm create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1238-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2007-1245-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-2.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-3.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf create mode 100644 vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm create mode 100644 vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm create mode 100644 vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm create mode 100644 vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore create mode 100644 vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm create mode 100644 vcl/qa/cppunit/graphicfilter/filters-test.cxx create mode 100644 vcl/qa/cppunit/jpeg/JpegReaderTest.cxx create mode 100644 vcl/qa/cppunit/jpeg/JpegWriterTest.cxx create mode 100644 vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg create mode 100644 vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif create mode 100644 vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg create mode 100644 vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg create mode 100644 vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg create mode 100644 vcl/qa/cppunit/lifecycle.cxx create mode 100644 vcl/qa/cppunit/mnemonic.cxx create mode 100644 vcl/qa/cppunit/outdev.cxx create mode 100644 vcl/qa/cppunit/pdfexport/data/6m-wide.odg create mode 100644 vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf create mode 100644 vcl/qa/cppunit/pdfexport/data/forcepoint71.key create mode 100644 vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf create mode 100644 vcl/qa/cppunit/pdfexport/data/reduce-image.fodt create mode 100644 vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt create mode 100644 vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf105093.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf105461.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf105954.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106059.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106206.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106693.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106702.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf106972.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf107013.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf107018.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf107089.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf107868.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf108963.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf109143.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf113143.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf115262.ods create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf115967.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf121615.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf121962.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf128630.odp create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/tdf99680.odt create mode 100644 vcl/qa/cppunit/pdfexport/data/toc-link.fodt create mode 100644 vcl/qa/cppunit/pdfexport/pdfexport.cxx create mode 100644 vcl/qa/cppunit/png/PngFilterTest.cxx create mode 100644 vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png create mode 100644 vcl/qa/cppunit/png/data/color-rect-4bit-pal.png create mode 100644 vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png create mode 100644 vcl/qa/cppunit/png/data/rect-1bit-pal.png create mode 100644 vcl/qa/cppunit/svm/data/arc.svm create mode 100644 vcl/qa/cppunit/svm/data/bitmapexs.svm create mode 100644 vcl/qa/cppunit/svm/data/bitmaps.svm create mode 100644 vcl/qa/cppunit/svm/data/chord.svm create mode 100644 vcl/qa/cppunit/svm/data/clipregion.svm create mode 100644 vcl/qa/cppunit/svm/data/ellipse.svm create mode 100644 vcl/qa/cppunit/svm/data/fillcolor.svm create mode 100644 vcl/qa/cppunit/svm/data/gradient.svm create mode 100644 vcl/qa/cppunit/svm/data/hatch.svm create mode 100644 vcl/qa/cppunit/svm/data/line.svm create mode 100644 vcl/qa/cppunit/svm/data/linecolor.svm create mode 100644 vcl/qa/cppunit/svm/data/masks.svm create mode 100644 vcl/qa/cppunit/svm/data/overlinecolor.svm create mode 100644 vcl/qa/cppunit/svm/data/pie.svm create mode 100644 vcl/qa/cppunit/svm/data/pixel.svm create mode 100644 vcl/qa/cppunit/svm/data/point.svm create mode 100644 vcl/qa/cppunit/svm/data/polygon.svm create mode 100644 vcl/qa/cppunit/svm/data/polyline.svm create mode 100644 vcl/qa/cppunit/svm/data/polypolygon.svm create mode 100644 vcl/qa/cppunit/svm/data/pushpop.svm create mode 100644 vcl/qa/cppunit/svm/data/rasterop.svm create mode 100644 vcl/qa/cppunit/svm/data/rect.svm create mode 100644 vcl/qa/cppunit/svm/data/roundrect.svm create mode 100644 vcl/qa/cppunit/svm/data/strecthtext.svm create mode 100644 vcl/qa/cppunit/svm/data/text.svm create mode 100644 vcl/qa/cppunit/svm/data/textalign.svm create mode 100644 vcl/qa/cppunit/svm/data/textarray.svm create mode 100644 vcl/qa/cppunit/svm/data/textcolor.svm create mode 100644 vcl/qa/cppunit/svm/data/textfillecolor.svm create mode 100644 vcl/qa/cppunit/svm/data/textline.svm create mode 100644 vcl/qa/cppunit/svm/data/textlinecolor.svm create mode 100644 vcl/qa/cppunit/svm/data/textrectangle.svm create mode 100644 vcl/qa/cppunit/svm/data/transparent.svm create mode 100644 vcl/qa/cppunit/svm/data/wallpaper.svm create mode 100644 vcl/qa/cppunit/svm/svmtest.cxx create mode 100644 vcl/qa/cppunit/test_blocklist_evaluate.xml create mode 100644 vcl/qa/cppunit/test_blocklist_parse.xml create mode 100644 vcl/qa/cppunit/timer.cxx create mode 100644 vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx create mode 100644 vcl/qa/cppunit/widgetdraw/data/definition1.xml create mode 100644 vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml create mode 100644 vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml create mode 100644 vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml create mode 100644 vcl/qa/unit/data/vcl-dialogs-test.txt create mode 100644 vcl/qa/unit/vcl-dialogs-test.cxx create mode 100644 vcl/qt5/Qt5AccessibleEventListener.cxx create mode 100644 vcl/qt5/Qt5AccessibleWidget.cxx create mode 100644 vcl/qt5/Qt5Bitmap.cxx create mode 100644 vcl/qt5/Qt5Clipboard.cxx create mode 100644 vcl/qt5/Qt5Data.cxx create mode 100644 vcl/qt5/Qt5DragAndDrop.cxx create mode 100644 vcl/qt5/Qt5FilePicker.cxx create mode 100644 vcl/qt5/Qt5Font.cxx create mode 100644 vcl/qt5/Qt5FontFace.cxx create mode 100644 vcl/qt5/Qt5Frame.cxx create mode 100644 vcl/qt5/Qt5Graphics.cxx create mode 100644 vcl/qt5/Qt5Graphics_Controls.cxx create mode 100644 vcl/qt5/Qt5Graphics_GDI.cxx create mode 100644 vcl/qt5/Qt5Graphics_Text.cxx create mode 100644 vcl/qt5/Qt5Instance.cxx create mode 100644 vcl/qt5/Qt5Instance_Print.cxx create mode 100644 vcl/qt5/Qt5MainWindow.cxx create mode 100644 vcl/qt5/Qt5Menu.cxx create mode 100644 vcl/qt5/Qt5Object.cxx create mode 100644 vcl/qt5/Qt5OpenGLContext.cxx create mode 100644 vcl/qt5/Qt5Painter.cxx create mode 100644 vcl/qt5/Qt5Printer.cxx create mode 100644 vcl/qt5/Qt5SvpGraphics.cxx create mode 100644 vcl/qt5/Qt5SvpSurface.cxx create mode 100644 vcl/qt5/Qt5SvpVirtualDevice.hxx create mode 100644 vcl/qt5/Qt5System.cxx create mode 100644 vcl/qt5/Qt5Timer.cxx create mode 100644 vcl/qt5/Qt5Tools.cxx create mode 100644 vcl/qt5/Qt5Transferable.cxx create mode 100644 vcl/qt5/Qt5VirtualDevice.cxx create mode 100644 vcl/qt5/Qt5Widget.cxx create mode 100644 vcl/qt5/Qt5XAccessible.cxx create mode 100644 vcl/quartz/ctfonts.cxx create mode 100644 vcl/quartz/salbmp.cxx create mode 100644 vcl/quartz/salgdi.cxx create mode 100644 vcl/quartz/salgdicommon.cxx create mode 100644 vcl/quartz/salgdiutils.cxx create mode 100644 vcl/quartz/salvd.cxx create mode 100644 vcl/quartz/utils.cxx create mode 100644 vcl/skia/README create mode 100644 vcl/skia/SkiaHelper.cxx create mode 100644 vcl/skia/gdiimpl.cxx create mode 100644 vcl/skia/salbmp.cxx create mode 100644 vcl/skia/skia_blacklist_vulkan.xml create mode 100644 vcl/skia/win/gdiimpl.cxx create mode 100644 vcl/skia/x11/gdiimpl.cxx create mode 100644 vcl/skia/x11/salvd.cxx create mode 100644 vcl/skia/x11/textrender.cxx create mode 100644 vcl/skia/zone.cxx create mode 100644 vcl/source/animate/Animation.cxx create mode 100644 vcl/source/animate/AnimationBitmap.cxx create mode 100644 vcl/source/app/ITiledRenderable.cxx create mode 100644 vcl/source/app/IconThemeInfo.cxx create mode 100644 vcl/source/app/IconThemeScanner.cxx create mode 100644 vcl/source/app/IconThemeSelector.cxx create mode 100644 vcl/source/app/brand.cxx create mode 100644 vcl/source/app/customweld.cxx create mode 100644 vcl/source/app/dbggui.cxx create mode 100644 vcl/source/app/dndhelp.cxx create mode 100644 vcl/source/app/help.cxx create mode 100644 vcl/source/app/i18nhelp.cxx create mode 100644 vcl/source/app/idle.cxx create mode 100644 vcl/source/app/salplug.cxx create mode 100644 vcl/source/app/salusereventlist.cxx create mode 100644 vcl/source/app/salvtables.cxx create mode 100644 vcl/source/app/scheduler.cxx create mode 100644 vcl/source/app/session.cxx create mode 100644 vcl/source/app/settings.cxx create mode 100644 vcl/source/app/sound.cxx create mode 100644 vcl/source/app/stdtext.cxx create mode 100644 vcl/source/app/svapp.cxx create mode 100644 vcl/source/app/svdata.cxx create mode 100644 vcl/source/app/svmain.cxx create mode 100644 vcl/source/app/timer.cxx create mode 100644 vcl/source/app/unohelp.cxx create mode 100644 vcl/source/app/unohelp2.cxx create mode 100644 vcl/source/app/vclevent.cxx create mode 100644 vcl/source/app/watchdog.cxx create mode 100644 vcl/source/app/weldutils.cxx create mode 100644 vcl/source/app/winscheduler.cxx create mode 100644 vcl/source/bitmap/BitmapAlphaClampFilter.cxx create mode 100644 vcl/source/bitmap/BitmapBasicMorphologyFilter.cxx create mode 100644 vcl/source/bitmap/BitmapColorQuantizationFilter.cxx create mode 100644 vcl/source/bitmap/BitmapColorizeFilter.cxx create mode 100644 vcl/source/bitmap/BitmapConvolutionMatrixFilter.cxx create mode 100644 vcl/source/bitmap/BitmapDisabledImageFilter.cxx create mode 100644 vcl/source/bitmap/BitmapDuoToneFilter.cxx create mode 100644 vcl/source/bitmap/BitmapEmbossGreyFilter.cxx create mode 100644 vcl/source/bitmap/BitmapFastScaleFilter.cxx create mode 100644 vcl/source/bitmap/BitmapFilterStackBlur.cxx create mode 100644 vcl/source/bitmap/BitmapGaussianSeparableBlurFilter.cxx create mode 100644 vcl/source/bitmap/BitmapInterpolateScaleFilter.cxx create mode 100644 vcl/source/bitmap/BitmapLightenFilter.cxx create mode 100644 vcl/source/bitmap/BitmapMedianFilter.cxx create mode 100644 vcl/source/bitmap/BitmapMonochromeFilter.cxx create mode 100644 vcl/source/bitmap/BitmapMosaicFilter.cxx create mode 100644 vcl/source/bitmap/BitmapPopArtFilter.cxx create mode 100644 vcl/source/bitmap/BitmapScaleConvolutionFilter.cxx create mode 100644 vcl/source/bitmap/BitmapScaleSuperFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSeparableUnsharpenFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSepiaFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSimpleColorQuantizationFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSmoothenFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSobelGreyFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSolarizeFilter.cxx create mode 100644 vcl/source/bitmap/BitmapSymmetryCheck.cxx create mode 100644 vcl/source/bitmap/BitmapTools.cxx create mode 100644 vcl/source/bitmap/Octree.cxx create mode 100644 vcl/source/bitmap/bitmap.cxx create mode 100644 vcl/source/bitmap/bitmapfilter.cxx create mode 100644 vcl/source/bitmap/bitmappaint.cxx create mode 100644 vcl/source/bitmap/checksum.cxx create mode 100644 vcl/source/bitmap/salbmp.cxx create mode 100644 vcl/source/components/dtranscomp.cxx create mode 100644 vcl/source/components/factory.cxx create mode 100644 vcl/source/components/fontident.cxx create mode 100644 vcl/source/control/InterimItemWindow.cxx create mode 100644 vcl/source/control/button.cxx create mode 100644 vcl/source/control/calendar.cxx create mode 100644 vcl/source/control/combobox.cxx create mode 100644 vcl/source/control/ctrl.cxx create mode 100644 vcl/source/control/edit.cxx create mode 100644 vcl/source/control/field.cxx create mode 100644 vcl/source/control/field2.cxx create mode 100644 vcl/source/control/fixed.cxx create mode 100644 vcl/source/control/fixedhyper.cxx create mode 100644 vcl/source/control/fmtfield.cxx create mode 100644 vcl/source/control/hyperlabel.cxx create mode 100644 vcl/source/control/imgctrl.cxx create mode 100644 vcl/source/control/imivctl.hxx create mode 100644 vcl/source/control/imivctl1.cxx create mode 100644 vcl/source/control/imivctl2.cxx create mode 100644 vcl/source/control/imp_listbox.cxx create mode 100644 vcl/source/control/ivctrl.cxx create mode 100644 vcl/source/control/listbox.cxx create mode 100644 vcl/source/control/longcurr.cxx create mode 100644 vcl/source/control/menubtn.cxx create mode 100644 vcl/source/control/notebookbar.cxx create mode 100644 vcl/source/control/prgsbar.cxx create mode 100644 vcl/source/control/quickselectionengine.cxx create mode 100644 vcl/source/control/roadmap.cxx create mode 100644 vcl/source/control/roadmapwizard.cxx create mode 100644 vcl/source/control/scrbar.cxx create mode 100644 vcl/source/control/slider.cxx create mode 100644 vcl/source/control/spinbtn.cxx create mode 100644 vcl/source/control/spinfld.cxx create mode 100644 vcl/source/control/tabctrl.cxx create mode 100644 vcl/source/control/throbber.cxx create mode 100644 vcl/source/control/thumbpos.hxx create mode 100644 vcl/source/control/wizardmachine.cxx create mode 100644 vcl/source/control/wizimpldata.hxx create mode 100644 vcl/source/edit/textdat2.hxx create mode 100644 vcl/source/edit/textdata.cxx create mode 100644 vcl/source/edit/textdoc.cxx create mode 100644 vcl/source/edit/textdoc.hxx create mode 100644 vcl/source/edit/texteng.cxx create mode 100644 vcl/source/edit/textund2.hxx create mode 100644 vcl/source/edit/textundo.cxx create mode 100644 vcl/source/edit/textundo.hxx create mode 100644 vcl/source/edit/textview.cxx create mode 100644 vcl/source/edit/txtattr.cxx create mode 100644 vcl/source/edit/vclmedit.cxx create mode 100644 vcl/source/edit/xtextedt.cxx create mode 100644 vcl/source/filter/FilterConfigCache.cxx create mode 100644 vcl/source/filter/FilterConfigCache.hxx create mode 100644 vcl/source/filter/FilterConfigItem.cxx create mode 100644 vcl/source/filter/GraphicFormatDetector.cxx create mode 100644 vcl/source/filter/GraphicNativeMetadata.cxx create mode 100644 vcl/source/filter/GraphicNativeTransform.cxx create mode 100644 vcl/source/filter/graphicfilter.cxx create mode 100644 vcl/source/filter/graphicfilter2.cxx create mode 100644 vcl/source/filter/graphicfilter_internal.hxx create mode 100644 vcl/source/filter/igif/decode.cxx create mode 100644 vcl/source/filter/igif/decode.hxx create mode 100644 vcl/source/filter/igif/gifread.cxx create mode 100644 vcl/source/filter/igif/gifread.hxx create mode 100644 vcl/source/filter/ipdf/pdfdocument.cxx create mode 100644 vcl/source/filter/ipdf/pdfread.cxx create mode 100644 vcl/source/filter/ixbm/xbmread.cxx create mode 100644 vcl/source/filter/ixbm/xbmread.hxx create mode 100644 vcl/source/filter/ixpm/rgbtable.hxx create mode 100644 vcl/source/filter/ixpm/xpmread.cxx create mode 100644 vcl/source/filter/ixpm/xpmread.hxx create mode 100644 vcl/source/filter/jpeg/Exif.cxx create mode 100644 vcl/source/filter/jpeg/Exif.hxx create mode 100644 vcl/source/filter/jpeg/JpegReader.cxx create mode 100644 vcl/source/filter/jpeg/JpegReader.hxx create mode 100644 vcl/source/filter/jpeg/JpegTransform.cxx create mode 100644 vcl/source/filter/jpeg/JpegTransform.hxx create mode 100644 vcl/source/filter/jpeg/JpegWriter.cxx create mode 100644 vcl/source/filter/jpeg/JpegWriter.hxx create mode 100644 vcl/source/filter/jpeg/jinclude.h create mode 100644 vcl/source/filter/jpeg/jpeg.cxx create mode 100644 vcl/source/filter/jpeg/jpeg.h create mode 100644 vcl/source/filter/jpeg/jpeg.hxx create mode 100644 vcl/source/filter/jpeg/jpegc.cxx create mode 100644 vcl/source/filter/jpeg/jpegcomp.h create mode 100644 vcl/source/filter/jpeg/transupp.c create mode 100644 vcl/source/filter/jpeg/transupp.h create mode 100644 vcl/source/filter/png/PngImageReader.cxx create mode 100644 vcl/source/filter/png/pngread.cxx create mode 100644 vcl/source/filter/png/pngwrite.cxx create mode 100644 vcl/source/filter/wmf/emfwr.cxx create mode 100644 vcl/source/filter/wmf/emfwr.hxx create mode 100644 vcl/source/filter/wmf/wmf.cxx create mode 100644 vcl/source/filter/wmf/wmfexternal.cxx create mode 100644 vcl/source/filter/wmf/wmfwr.cxx create mode 100644 vcl/source/filter/wmf/wmfwr.hxx create mode 100644 vcl/source/font/Feature.cxx create mode 100644 vcl/source/font/FeatureCollector.cxx create mode 100644 vcl/source/font/FeatureParser.cxx create mode 100644 vcl/source/font/OpenTypeFeatureDefinitionList.cxx create mode 100644 vcl/source/font/PhysicalFontCollection.cxx create mode 100644 vcl/source/font/PhysicalFontFace.cxx create mode 100644 vcl/source/font/PhysicalFontFamily.cxx create mode 100644 vcl/source/font/font.cxx create mode 100644 vcl/source/font/fontattributes.cxx create mode 100644 vcl/source/font/fontcache.cxx create mode 100644 vcl/source/font/fontcharmap.cxx create mode 100644 vcl/source/font/fontinstance.cxx create mode 100644 vcl/source/font/fontmetric.cxx create mode 100644 vcl/source/font/fontselect.cxx create mode 100644 vcl/source/fontsubset/cff.cxx create mode 100644 vcl/source/fontsubset/fontsubset.cxx create mode 100644 vcl/source/fontsubset/list.cxx create mode 100644 vcl/source/fontsubset/list.h create mode 100644 vcl/source/fontsubset/sft.cxx create mode 100644 vcl/source/fontsubset/ttcr.cxx create mode 100644 vcl/source/fontsubset/ttcr.hxx create mode 100644 vcl/source/fontsubset/xlat.cxx create mode 100644 vcl/source/fontsubset/xlat.hxx create mode 100644 vcl/source/gdi/CommonSalLayout.cxx create mode 100644 vcl/source/gdi/FileDefinitionWidgetDraw.cxx create mode 100644 vcl/source/gdi/TypeSerializer.cxx create mode 100644 vcl/source/gdi/VerticalOrientationData.cxx create mode 100644 vcl/source/gdi/WidgetDefinition.cxx create mode 100644 vcl/source/gdi/WidgetDefinitionReader.cxx create mode 100644 vcl/source/gdi/alpha.cxx create mode 100644 vcl/source/gdi/bitmap3.cxx create mode 100644 vcl/source/gdi/bitmapex.cxx create mode 100644 vcl/source/gdi/bmpacc.cxx create mode 100644 vcl/source/gdi/bmpacc2.cxx create mode 100644 vcl/source/gdi/bmpacc3.cxx create mode 100644 vcl/source/gdi/bmpfast.cxx create mode 100644 vcl/source/gdi/configsettings.cxx create mode 100644 vcl/source/gdi/cvtgrf.cxx create mode 100644 vcl/source/gdi/dibtools.cxx create mode 100644 vcl/source/gdi/embeddedfontshelper.cxx create mode 100644 vcl/source/gdi/extoutdevdata.cxx create mode 100644 vcl/source/gdi/gdimetafiletools.cxx create mode 100644 vcl/source/gdi/gdimtf.cxx create mode 100755 vcl/source/gdi/genVerticalOrientationData.pl create mode 100644 vcl/source/gdi/gfxlink.cxx create mode 100644 vcl/source/gdi/gradient.cxx create mode 100644 vcl/source/gdi/graph.cxx create mode 100644 vcl/source/gdi/graphictools.cxx create mode 100644 vcl/source/gdi/hatch.cxx create mode 100644 vcl/source/gdi/impanmvw.cxx create mode 100644 vcl/source/gdi/impglyphitem.cxx create mode 100644 vcl/source/gdi/impgraph.cxx create mode 100644 vcl/source/gdi/impvect.cxx create mode 100644 vcl/source/gdi/impvect.hxx create mode 100644 vcl/source/gdi/jobset.cxx create mode 100644 vcl/source/gdi/lineinfo.cxx create mode 100644 vcl/source/gdi/mapmod.cxx create mode 100644 vcl/source/gdi/metaact.cxx create mode 100644 vcl/source/gdi/mtfxmldump.cxx create mode 100644 vcl/source/gdi/oldprintadaptor.cxx create mode 100644 vcl/source/gdi/pdfbuildin_fonts.cxx create mode 100644 vcl/source/gdi/pdfbuildin_fonts.hxx create mode 100644 vcl/source/gdi/pdfextoutdevdata.cxx create mode 100644 vcl/source/gdi/pdffontcache.cxx create mode 100644 vcl/source/gdi/pdffontcache.hxx create mode 100644 vcl/source/gdi/pdfwriter.cxx create mode 100644 vcl/source/gdi/pdfwriter_impl.cxx create mode 100644 vcl/source/gdi/pdfwriter_impl.hxx create mode 100644 vcl/source/gdi/pdfwriter_impl2.cxx create mode 100644 vcl/source/gdi/print.cxx create mode 100644 vcl/source/gdi/print2.cxx create mode 100644 vcl/source/gdi/print3.cxx create mode 100644 vcl/source/gdi/regband.cxx create mode 100644 vcl/source/gdi/region.cxx create mode 100644 vcl/source/gdi/regionband.cxx create mode 100644 vcl/source/gdi/salgdiimpl.cxx create mode 100644 vcl/source/gdi/salgdilayout.cxx create mode 100644 vcl/source/gdi/sallayout.cxx create mode 100644 vcl/source/gdi/salmisc.cxx create mode 100644 vcl/source/gdi/scrptrun.cxx create mode 100644 vcl/source/gdi/svmconverter.cxx create mode 100644 vcl/source/gdi/textlayout.cxx create mode 100644 vcl/source/gdi/vectorgraphicdata.cxx create mode 100644 vcl/source/gdi/virdev.cxx create mode 100644 vcl/source/gdi/wall.cxx create mode 100644 vcl/source/graphic/GraphicID.cxx create mode 100644 vcl/source/graphic/GraphicLoader.cxx create mode 100644 vcl/source/graphic/GraphicObject.cxx create mode 100644 vcl/source/graphic/GraphicObject2.cxx create mode 100644 vcl/source/graphic/GraphicReader.cxx create mode 100644 vcl/source/graphic/Manager.cxx create mode 100644 vcl/source/graphic/UnoGraphic.cxx create mode 100644 vcl/source/graphic/UnoGraphicDescriptor.cxx create mode 100644 vcl/source/graphic/UnoGraphicObject.cxx create mode 100644 vcl/source/graphic/UnoGraphicProvider.cxx create mode 100644 vcl/source/graphic/UnoGraphicTransformer.cxx create mode 100644 vcl/source/graphic/grfattr.cxx create mode 100644 vcl/source/helper/canvasbitmap.cxx create mode 100644 vcl/source/helper/canvastools.cxx create mode 100644 vcl/source/helper/commandinfoprovider.cxx create mode 100644 vcl/source/helper/displayconnectiondispatch.cxx create mode 100644 vcl/source/helper/driverblocklist.cxx create mode 100644 vcl/source/helper/errcode.cxx create mode 100644 vcl/source/helper/evntpost.cxx create mode 100644 vcl/source/helper/lazydelete.cxx create mode 100644 vcl/source/helper/strhelper.cxx create mode 100644 vcl/source/helper/svtaccessiblefactory.cxx create mode 100644 vcl/source/helper/threadex.cxx create mode 100644 vcl/source/image/Image.cxx create mode 100644 vcl/source/image/ImageRepository.cxx create mode 100644 vcl/source/image/ImageTree.cxx create mode 100644 vcl/source/image/ImplImage.cxx create mode 100644 vcl/source/image/ImplImageTree.cxx create mode 100644 vcl/source/opengl/GLMHelper.hxx create mode 100644 vcl/source/opengl/OpenGLContext.cxx create mode 100644 vcl/source/opengl/OpenGLHelper.cxx create mode 100644 vcl/source/outdev/bitmap.cxx create mode 100644 vcl/source/outdev/clipping.cxx create mode 100644 vcl/source/outdev/curvedshapes.cxx create mode 100644 vcl/source/outdev/font.cxx create mode 100644 vcl/source/outdev/gradient.cxx create mode 100644 vcl/source/outdev/hatch.cxx create mode 100644 vcl/source/outdev/line.cxx create mode 100644 vcl/source/outdev/map.cxx create mode 100644 vcl/source/outdev/mask.cxx create mode 100644 vcl/source/outdev/nativecontrols.cxx create mode 100644 vcl/source/outdev/outdev.cxx create mode 100644 vcl/source/outdev/outdevstate.cxx create mode 100644 vcl/source/outdev/pixel.cxx create mode 100644 vcl/source/outdev/polygon.cxx create mode 100644 vcl/source/outdev/polyline.cxx create mode 100644 vcl/source/outdev/rect.cxx create mode 100644 vcl/source/outdev/text.cxx create mode 100644 vcl/source/outdev/textline.cxx create mode 100644 vcl/source/outdev/transparent.cxx create mode 100644 vcl/source/outdev/vclreferencebase.cxx create mode 100644 vcl/source/outdev/wallpaper.cxx create mode 100644 vcl/source/pdf/Matrix3.cxx create mode 100644 vcl/source/pdf/PDFiumLibrary.cxx create mode 100644 vcl/source/pdf/ResourceDict.cxx create mode 100644 vcl/source/pdf/XmpMetadata.cxx create mode 100644 vcl/source/salmain/salmain.cxx create mode 100644 vcl/source/toolkit/README create mode 100644 vcl/source/toolkit/group.cxx create mode 100644 vcl/source/toolkit/morebtn.cxx create mode 100644 vcl/source/treelist/headbar.cxx create mode 100644 vcl/source/treelist/iconview.cxx create mode 100644 vcl/source/treelist/iconviewimpl.cxx create mode 100644 vcl/source/treelist/iconviewimpl.hxx create mode 100644 vcl/source/treelist/imap.cxx create mode 100644 vcl/source/treelist/imap2.cxx create mode 100644 vcl/source/treelist/imap3.cxx create mode 100644 vcl/source/treelist/inetimg.cxx create mode 100644 vcl/source/treelist/svimpbox.cxx create mode 100644 vcl/source/treelist/svlbitm.cxx create mode 100644 vcl/source/treelist/svtabbx.cxx create mode 100644 vcl/source/treelist/transfer.cxx create mode 100644 vcl/source/treelist/transfer2.cxx create mode 100644 vcl/source/treelist/treelist.cxx create mode 100644 vcl/source/treelist/treelistbox.cxx create mode 100644 vcl/source/treelist/treelistentry.cxx create mode 100644 vcl/source/treelist/uiobject.cxx create mode 100644 vcl/source/treelist/viewdataentry.cxx create mode 100644 vcl/source/uipreviewer/previewer.cxx create mode 100644 vcl/source/uitest/logger.cxx create mode 100644 vcl/source/uitest/uiobject.cxx create mode 100644 vcl/source/uitest/uitest.cxx create mode 100644 vcl/source/uitest/uno/uiobject_uno.cxx create mode 100644 vcl/source/uitest/uno/uiobject_uno.hxx create mode 100644 vcl/source/uitest/uno/uitest_uno.cxx create mode 100644 vcl/source/window/EnumContext.cxx create mode 100644 vcl/source/window/NotebookBarAddonsMerger.cxx create mode 100644 vcl/source/window/OptionalBox.cxx create mode 100644 vcl/source/window/abstdlg.cxx create mode 100644 vcl/source/window/accel.cxx create mode 100644 vcl/source/window/accessibility.cxx create mode 100644 vcl/source/window/accmgr.cxx create mode 100644 vcl/source/window/brdwin.cxx create mode 100644 vcl/source/window/bufferdevice.cxx create mode 100644 vcl/source/window/bufferdevice.hxx create mode 100644 vcl/source/window/builder.cxx create mode 100644 vcl/source/window/clipping.cxx create mode 100644 vcl/source/window/commandevent.cxx create mode 100644 vcl/source/window/cursor.cxx create mode 100644 vcl/source/window/debug.cxx create mode 100644 vcl/source/window/debugevent.cxx create mode 100644 vcl/source/window/decoview.cxx create mode 100644 vcl/source/window/dialog.cxx create mode 100644 vcl/source/window/dlgctrl.cxx create mode 100644 vcl/source/window/dlgctrl.hxx create mode 100644 vcl/source/window/dndeventdispatcher.cxx create mode 100644 vcl/source/window/dndlistenercontainer.cxx create mode 100644 vcl/source/window/dockingarea.cxx create mode 100644 vcl/source/window/dockmgr.cxx create mode 100644 vcl/source/window/dockwin.cxx create mode 100644 vcl/source/window/errinf.cxx create mode 100644 vcl/source/window/event.cxx create mode 100644 vcl/source/window/floatwin.cxx create mode 100644 vcl/source/window/globalization.cxx create mode 100644 vcl/source/window/introwin.cxx create mode 100644 vcl/source/window/keycod.cxx create mode 100644 vcl/source/window/keyevent.cxx create mode 100644 vcl/source/window/layout.cxx create mode 100644 vcl/source/window/legacyaccessibility.cxx create mode 100644 vcl/source/window/menu.cxx create mode 100644 vcl/source/window/menubarwindow.cxx create mode 100644 vcl/source/window/menubarwindow.hxx create mode 100644 vcl/source/window/menufloatingwindow.cxx create mode 100644 vcl/source/window/menufloatingwindow.hxx create mode 100644 vcl/source/window/menuitemlist.cxx create mode 100644 vcl/source/window/menuitemlist.hxx create mode 100644 vcl/source/window/menuwindow.cxx create mode 100644 vcl/source/window/menuwindow.hxx create mode 100644 vcl/source/window/mnemonic.cxx create mode 100644 vcl/source/window/mnemonicengine.cxx create mode 100644 vcl/source/window/mouse.cxx create mode 100644 vcl/source/window/paint.cxx create mode 100644 vcl/source/window/popupmenuwindow.cxx create mode 100644 vcl/source/window/printdlg.cxx create mode 100644 vcl/source/window/scrwnd.cxx create mode 100644 vcl/source/window/seleng.cxx create mode 100644 vcl/source/window/settings.cxx create mode 100644 vcl/source/window/split.cxx create mode 100644 vcl/source/window/splitwin.cxx create mode 100644 vcl/source/window/stacking.cxx create mode 100644 vcl/source/window/status.cxx create mode 100644 vcl/source/window/syschild.cxx create mode 100644 vcl/source/window/syswin.cxx create mode 100644 vcl/source/window/tabdlg.cxx create mode 100644 vcl/source/window/tabpage.cxx create mode 100644 vcl/source/window/taskpanelist.cxx create mode 100644 vcl/source/window/toolbox.cxx create mode 100644 vcl/source/window/toolbox2.cxx create mode 100644 vcl/source/window/window.cxx create mode 100644 vcl/source/window/window2.cxx create mode 100644 vcl/source/window/window3.cxx create mode 100644 vcl/source/window/winproc.cxx create mode 100644 vcl/source/window/wrkwin.cxx create mode 100644 vcl/uiconfig/theme_definitions/ios/arrow-down.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/arrow-up.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/combobox-button-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/combobox-button.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/combobox-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/combobox.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/common-rect-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/common-rect-focus-slim.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/common-rect-focus.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/common-rect.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/definition.xml create mode 100644 vcl/uiconfig/theme_definitions/ios/pushbutton-default.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/pushbutton-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/pushbutton-rollover.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/scrollbar-horizontal.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/scrollbar-vertical.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/slider-button-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/slider-button.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-left-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-left-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-left.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-right-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-right-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/spinbox-right.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-off-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-off-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-off.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-on-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-on-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/switch-on.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-first-selected.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-first.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-last-selected.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-last.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-middle-selected.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tabitem-middle.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-off-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-off-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-off.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-on-disabled.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-on-pressed.svg create mode 100644 vcl/uiconfig/theme_definitions/ios/tick-on.svg create mode 100644 vcl/uiconfig/ui/aboutbox.ui create mode 100644 vcl/uiconfig/ui/combobox.ui create mode 100644 vcl/uiconfig/ui/cupspassworddialog.ui create mode 100644 vcl/uiconfig/ui/editmenu.ui create mode 100644 vcl/uiconfig/ui/errornocontentdialog.ui create mode 100644 vcl/uiconfig/ui/errornoprinterdialog.ui create mode 100644 vcl/uiconfig/ui/moreoptionsdialog.ui create mode 100644 vcl/uiconfig/ui/printdialog.ui create mode 100644 vcl/uiconfig/ui/printerdevicepage.ui create mode 100644 vcl/uiconfig/ui/printerpaperpage.ui create mode 100644 vcl/uiconfig/ui/printerpropertiesdialog.ui create mode 100644 vcl/uiconfig/ui/printprogressdialog.ui create mode 100644 vcl/uiconfig/ui/querydialog.ui create mode 100644 vcl/uiconfig/ui/screenshotparent.ui create mode 100644 vcl/uiconfig/ui/wizard.ui create mode 100644 vcl/unx/generic/app/gendata.cxx create mode 100644 vcl/unx/generic/app/gendisp.cxx create mode 100644 vcl/unx/generic/app/geninst.cxx create mode 100644 vcl/unx/generic/app/gensys.cxx create mode 100644 vcl/unx/generic/app/i18n_cb.cxx create mode 100644 vcl/unx/generic/app/i18n_ic.cxx create mode 100644 vcl/unx/generic/app/i18n_im.cxx create mode 100644 vcl/unx/generic/app/i18n_keysym.cxx create mode 100644 vcl/unx/generic/app/i18n_xkb.cxx create mode 100644 vcl/unx/generic/app/keysymnames.cxx create mode 100644 vcl/unx/generic/app/randrwrapper.cxx create mode 100644 vcl/unx/generic/app/saldata.cxx create mode 100644 vcl/unx/generic/app/saldisp.cxx create mode 100644 vcl/unx/generic/app/salinst.cxx create mode 100644 vcl/unx/generic/app/saltimer.cxx create mode 100644 vcl/unx/generic/app/sm.cxx create mode 100644 vcl/unx/generic/app/wmadaptor.cxx create mode 100644 vcl/unx/generic/desktopdetect/desktopdetector.cxx create mode 100644 vcl/unx/generic/dtrans/X11_clipboard.cxx create mode 100644 vcl/unx/generic/dtrans/X11_clipboard.hxx create mode 100644 vcl/unx/generic/dtrans/X11_dndcontext.cxx create mode 100644 vcl/unx/generic/dtrans/X11_dndcontext.hxx create mode 100644 vcl/unx/generic/dtrans/X11_droptarget.cxx create mode 100644 vcl/unx/generic/dtrans/X11_selection.cxx create mode 100644 vcl/unx/generic/dtrans/X11_selection.hxx create mode 100644 vcl/unx/generic/dtrans/X11_service.cxx create mode 100644 vcl/unx/generic/dtrans/X11_transferable.cxx create mode 100644 vcl/unx/generic/dtrans/X11_transferable.hxx create mode 100644 vcl/unx/generic/dtrans/bmp.cxx create mode 100644 vcl/unx/generic/dtrans/bmp.hxx create mode 100644 vcl/unx/generic/dtrans/config.cxx create mode 100644 vcl/unx/generic/dtrans/copydata_curs.h create mode 100644 vcl/unx/generic/dtrans/copydata_mask.h create mode 100644 vcl/unx/generic/dtrans/linkdata_curs.h create mode 100644 vcl/unx/generic/dtrans/linkdata_mask.h create mode 100644 vcl/unx/generic/dtrans/movedata_curs.h create mode 100644 vcl/unx/generic/dtrans/movedata_mask.h create mode 100644 vcl/unx/generic/dtrans/nodrop_curs.h create mode 100644 vcl/unx/generic/dtrans/nodrop_mask.h create mode 100644 vcl/unx/generic/fontmanager/fontconfig.cxx create mode 100644 vcl/unx/generic/fontmanager/fontmanager.cxx create mode 100644 vcl/unx/generic/fontmanager/fontsubst.cxx create mode 100644 vcl/unx/generic/fontmanager/helper.cxx create mode 100644 vcl/unx/generic/gdi/cairo_xlib_cairo.cxx create mode 100644 vcl/unx/generic/gdi/cairo_xlib_cairo.hxx create mode 100644 vcl/unx/generic/gdi/cairotextrender.cxx create mode 100644 vcl/unx/generic/gdi/font.cxx create mode 100644 vcl/unx/generic/gdi/freetypetextrender.cxx create mode 100644 vcl/unx/generic/gdi/gdiimpl.cxx create mode 100644 vcl/unx/generic/gdi/gdiimpl.hxx create mode 100644 vcl/unx/generic/gdi/nativewindowhandleprovider.cxx create mode 100644 vcl/unx/generic/gdi/salbmp.cxx create mode 100644 vcl/unx/generic/gdi/salgdi.cxx create mode 100644 vcl/unx/generic/gdi/salgdi2.cxx create mode 100644 vcl/unx/generic/gdi/salvd.cxx create mode 100644 vcl/unx/generic/gdi/x11cairotextrender.cxx create mode 100644 vcl/unx/generic/gdi/xrender_peer.cxx create mode 100644 vcl/unx/generic/glyphs/freetype_glyphcache.cxx create mode 100644 vcl/unx/generic/glyphs/glyphcache.cxx create mode 100644 vcl/unx/generic/print/bitmap_gfx.cxx create mode 100644 vcl/unx/generic/print/common_gfx.cxx create mode 100644 vcl/unx/generic/print/genprnpsp.cxx create mode 100644 vcl/unx/generic/print/genpspgraphics.cxx create mode 100644 vcl/unx/generic/print/glyphset.cxx create mode 100644 vcl/unx/generic/print/glyphset.hxx create mode 100644 vcl/unx/generic/print/printerjob.cxx create mode 100644 vcl/unx/generic/print/prtsetup.cxx create mode 100644 vcl/unx/generic/print/prtsetup.hxx create mode 100644 vcl/unx/generic/print/psheader.ps create mode 100644 vcl/unx/generic/print/psputil.cxx create mode 100644 vcl/unx/generic/print/psputil.hxx create mode 100644 vcl/unx/generic/print/text_gfx.cxx create mode 100644 vcl/unx/generic/printer/configuration/README create mode 100644 vcl/unx/generic/printer/configuration/ppds/SGENPRT.PS create mode 100644 vcl/unx/generic/printer/configuration/psprint.conf create mode 100644 vcl/unx/generic/printer/cpdmgr.cxx create mode 100644 vcl/unx/generic/printer/cupsmgr.cxx create mode 100644 vcl/unx/generic/printer/jobdata.cxx create mode 100644 vcl/unx/generic/printer/ppdparser.cxx create mode 100644 vcl/unx/generic/printer/printerinfomanager.cxx create mode 100644 vcl/unx/generic/window/salframe.cxx create mode 100644 vcl/unx/generic/window/salobj.cxx create mode 100644 vcl/unx/generic/window/screensaverinhibitor.cxx create mode 100644 vcl/unx/glxtest.cxx create mode 100644 vcl/unx/gtk3/a11y/TODO create mode 100644 vcl/unx/gtk3/a11y/atkfactory.hxx create mode 100644 vcl/unx/gtk3/a11y/atklistener.hxx create mode 100644 vcl/unx/gtk3/a11y/atkregistry.hxx create mode 100644 vcl/unx/gtk3/a11y/atktextattributes.hxx create mode 100644 vcl/unx/gtk3/a11y/atkutil.hxx create mode 100644 vcl/unx/gtk3/a11y/atkwrapper.hxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkaction.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkbridge.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkcomponent.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkeditabletext.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkfactory.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkhypertext.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkimage.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atklistener.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkregistry.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkselection.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atktable.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atktext.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atktextattributes.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkutil.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkvalue.cxx create mode 100644 vcl/unx/gtk3/a11y/gtk3atkwrapper.cxx create mode 100644 vcl/unx/gtk3/cairo_gtk3_cairo.cxx create mode 100644 vcl/unx/gtk3/cairo_gtk3_cairo.hxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkFilePicker.cxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkFilePicker.hxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkFolderPicker.cxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkFolderPicker.hxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkPicker.cxx create mode 100644 vcl/unx/gtk3/fpicker/SalGtkPicker.hxx create mode 100644 vcl/unx/gtk3/fpicker/eventnotification.hxx create mode 100644 vcl/unx/gtk3/fpicker/resourceprovider.cxx create mode 100644 vcl/unx/gtk3/gtk3gloactiongroup.cxx create mode 100644 vcl/unx/gtk3/gtk3glomenu.cxx create mode 100644 vcl/unx/gtk3/gtk3gtkdata.cxx create mode 100644 vcl/unx/gtk3/gtk3gtkframe.cxx create mode 100644 vcl/unx/gtk3/gtk3gtkinst.cxx create mode 100644 vcl/unx/gtk3/gtk3gtkobject.cxx create mode 100644 vcl/unx/gtk3/gtk3gtkprintwrapper.cxx create mode 100644 vcl/unx/gtk3/gtk3gtksalmenu.cxx create mode 100644 vcl/unx/gtk3/gtk3gtksys.cxx create mode 100644 vcl/unx/gtk3/gtk3hudawareness.cxx create mode 100644 vcl/unx/gtk3/gtk3salnativewidgets-gtk.cxx create mode 100644 vcl/unx/gtk3/gtk3salprn-gtk.cxx create mode 100644 vcl/unx/gtk3/gtkprintwrapper.hxx create mode 100644 vcl/unx/gtk3_kde5/FPServiceInfo.hxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkaction.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkbridge.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkcomponent.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkeditabletext.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkfactory.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkhypertext.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkimage.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atklistener.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkregistry.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkselection.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktable.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktext.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktextattributes.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkutil.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkvalue.cxx create mode 100644 vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkwrapper.cxx create mode 100644 vcl/unx/gtk3_kde5/filepicker_ipc_commands.hxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_a11y.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_cairo.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_filepicker.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_filepicker.hxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc.hxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_folderpicker.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_folderpicker.hxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gloactiongroup.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_glomenu.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtkdata.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtkframe.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtkinst.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtkobject.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtksalmenu.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_gtksys.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_hudawareness.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_printwrapper.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_salnativewidgets-gtk.cxx create mode 100644 vcl/unx/gtk3_kde5/gtk3_kde5_salprn-gtk.cxx create mode 100644 vcl/unx/gtk3_kde5/kde5_filepicker.cxx create mode 100644 vcl/unx/gtk3_kde5/kde5_filepicker.hxx create mode 100644 vcl/unx/gtk3_kde5/kde5_filepicker_ipc.cxx create mode 100644 vcl/unx/gtk3_kde5/kde5_filepicker_ipc.hxx create mode 100644 vcl/unx/gtk3_kde5/kde5_lo_filepicker_main.cxx create mode 100644 vcl/unx/kf5/KF5FilePicker.cxx create mode 100644 vcl/unx/kf5/KF5FilePicker.hxx create mode 100644 vcl/unx/kf5/KF5SalFrame.cxx create mode 100644 vcl/unx/kf5/KF5SalFrame.hxx create mode 100644 vcl/unx/kf5/KF5SalInstance.cxx create mode 100644 vcl/unx/kf5/KF5SalInstance.hxx create mode 100644 vcl/unx/x11/x11sys.cxx create mode 100644 vcl/unx/x11/xlimits.cxx create mode 100644 vcl/vcl.android.component create mode 100644 vcl/vcl.common.component create mode 100644 vcl/vcl.headless.component create mode 100644 vcl/vcl.ios.component create mode 100644 vcl/vcl.macosx.component create mode 100644 vcl/vcl.unx.component create mode 100644 vcl/vcl.windows.component create mode 100644 vcl/win/app/saldata.cxx create mode 100644 vcl/win/app/salinfo.cxx create mode 100644 vcl/win/app/salinst.cxx create mode 100644 vcl/win/app/salshl.cxx create mode 100644 vcl/win/app/saltimer.cxx create mode 100644 vcl/win/gdi/DWriteTextRenderer.cxx create mode 100644 vcl/win/gdi/gdiimpl.cxx create mode 100644 vcl/win/gdi/gdiimpl.hxx create mode 100644 vcl/win/gdi/salbmp.cxx create mode 100644 vcl/win/gdi/salfont.cxx create mode 100644 vcl/win/gdi/salgdi.cxx create mode 100644 vcl/win/gdi/salgdi2.cxx create mode 100644 vcl/win/gdi/salgdi_gdiplus.cxx create mode 100644 vcl/win/gdi/salnativewidgets-luna.cxx create mode 100644 vcl/win/gdi/salprn.cxx create mode 100644 vcl/win/gdi/salvd.cxx create mode 100644 vcl/win/gdi/winlayout.cxx create mode 100644 vcl/win/src/50.bmp create mode 100644 vcl/win/src/50.png create mode 100644 vcl/win/src/ase.cur create mode 100644 vcl/win/src/asn.cur create mode 100644 vcl/win/src/asne.cur create mode 100644 vcl/win/src/asns.cur create mode 100644 vcl/win/src/asnswe.cur create mode 100644 vcl/win/src/asnw.cur create mode 100644 vcl/win/src/ass.cur create mode 100644 vcl/win/src/asse.cur create mode 100644 vcl/win/src/assw.cur create mode 100644 vcl/win/src/asw.cur create mode 100644 vcl/win/src/aswe.cur create mode 100644 vcl/win/src/chain.cur create mode 100644 vcl/win/src/chainnot.cur create mode 100644 vcl/win/src/chart.cur create mode 100644 vcl/win/src/copydata.cur create mode 100644 vcl/win/src/copydlnk.cur create mode 100644 vcl/win/src/copyf.cur create mode 100644 vcl/win/src/copyf2.cur create mode 100644 vcl/win/src/copyflnk.cur create mode 100644 vcl/win/src/crook.cur create mode 100644 vcl/win/src/crop.cur create mode 100644 vcl/win/src/darc.cur create mode 100644 vcl/win/src/dbezier.cur create mode 100644 vcl/win/src/dcapt.cur create mode 100644 vcl/win/src/dcirccut.cur create mode 100644 vcl/win/src/dconnect.cur create mode 100644 vcl/win/src/dellipse.cur create mode 100644 vcl/win/src/detectiv.cur create mode 100644 vcl/win/src/dfree.cur create mode 100644 vcl/win/src/dline.cur create mode 100644 vcl/win/src/dpie.cur create mode 100644 vcl/win/src/dpolygon.cur create mode 100644 vcl/win/src/drect.cur create mode 100644 vcl/win/src/dtext.cur create mode 100644 vcl/win/src/fill.cur create mode 100644 vcl/win/src/hshear.cur create mode 100644 vcl/win/src/linkdata.cur create mode 100644 vcl/win/src/linkf.cur create mode 100644 vcl/win/src/magnify.cur create mode 100644 vcl/win/src/mirror.cur create mode 100644 vcl/win/src/movebw.cur create mode 100644 vcl/win/src/movedata.cur create mode 100644 vcl/win/src/movedlnk.cur create mode 100644 vcl/win/src/movef.cur create mode 100644 vcl/win/src/movef2.cur create mode 100644 vcl/win/src/moveflnk.cur create mode 100644 vcl/win/src/movept.cur create mode 100644 vcl/win/src/nullptr.cur create mode 100644 vcl/win/src/pivotcol.cur create mode 100644 vcl/win/src/pivotdel.cur create mode 100644 vcl/win/src/pivotfld.cur create mode 100644 vcl/win/src/pivotrow.cur create mode 100644 vcl/win/src/rotate.cur create mode 100644 vcl/win/src/salsrc.rc create mode 100644 vcl/win/src/sd.ico create mode 100644 vcl/win/src/tblsele.cur create mode 100644 vcl/win/src/tblsels.cur create mode 100644 vcl/win/src/tblselse.cur create mode 100644 vcl/win/src/tblselsw.cur create mode 100644 vcl/win/src/tblselw.cur create mode 100644 vcl/win/src/vshear.cur create mode 100644 vcl/win/src/vtext.cur create mode 100644 vcl/win/src/wshide.cur create mode 100644 vcl/win/src/wsshow.cur create mode 100644 vcl/win/window/keynames.cxx create mode 100644 vcl/win/window/salframe.cxx create mode 100644 vcl/win/window/salmenu.cxx create mode 100644 vcl/win/window/salobj.cxx create mode 100644 vcl/workben/602fuzzer.cxx create mode 100644 vcl/workben/602fuzzer.options create mode 100644 vcl/workben/bmpfuzzer.cxx create mode 100644 vcl/workben/bmpfuzzer.options create mode 100644 vcl/workben/cgmfuzzer.cxx create mode 100644 vcl/workben/cgmfuzzer.options create mode 100644 vcl/workben/commonfuzzer.hxx create mode 100644 vcl/workben/diffuzzer.cxx create mode 100644 vcl/workben/diffuzzer.options create mode 100644 vcl/workben/docxfuzzer.cxx create mode 100644 vcl/workben/docxfuzzer.options create mode 100644 vcl/workben/dxffuzzer.cxx create mode 100644 vcl/workben/dxffuzzer.options create mode 100644 vcl/workben/epsfuzzer.cxx create mode 100644 vcl/workben/epsfuzzer.options create mode 100644 vcl/workben/fftester.cxx create mode 100644 vcl/workben/fodpfuzzer.cxx create mode 100644 vcl/workben/fodpfuzzer.options create mode 100644 vcl/workben/fodsfuzzer.cxx create mode 100644 vcl/workben/fodsfuzzer.options create mode 100644 vcl/workben/fodtfuzzer.cxx create mode 100644 vcl/workben/fodtfuzzer.options create mode 100644 vcl/workben/giffuzzer.cxx create mode 100644 vcl/workben/giffuzzer.options create mode 100644 vcl/workben/htmlfuzzer.cxx create mode 100644 vcl/workben/htmlfuzzer.options create mode 100644 vcl/workben/hwpfuzzer.cxx create mode 100644 vcl/workben/hwpfuzzer.options create mode 100644 vcl/workben/icontest.cxx create mode 100644 vcl/workben/jpgfuzzer.cxx create mode 100644 vcl/workben/jpgfuzzer.options create mode 100644 vcl/workben/localestub/localedata_en_AU.cxx create mode 100644 vcl/workben/localestub/localedata_en_BW.cxx create mode 100644 vcl/workben/localestub/localedata_en_BZ.cxx create mode 100644 vcl/workben/localestub/localedata_en_CA.cxx create mode 100644 vcl/workben/localestub/localedata_en_GB.cxx create mode 100644 vcl/workben/localestub/localedata_en_GH.cxx create mode 100644 vcl/workben/localestub/localedata_en_GM.cxx create mode 100644 vcl/workben/localestub/localedata_en_IE.cxx create mode 100644 vcl/workben/localestub/localedata_en_IN.cxx create mode 100644 vcl/workben/localestub/localedata_en_JM.cxx create mode 100644 vcl/workben/localestub/localedata_en_LK.cxx create mode 100644 vcl/workben/localestub/localedata_en_MW.cxx create mode 100644 vcl/workben/localestub/localedata_en_MY.cxx create mode 100644 vcl/workben/localestub/localedata_en_NA.cxx create mode 100644 vcl/workben/localestub/localedata_en_NG.cxx create mode 100644 vcl/workben/localestub/localedata_en_NZ.cxx create mode 100644 vcl/workben/localestub/localedata_en_PH.cxx create mode 100644 vcl/workben/localestub/localedata_en_TT.cxx create mode 100644 vcl/workben/localestub/localedata_en_US.cxx create mode 100644 vcl/workben/localestub/localedata_en_ZA.cxx create mode 100644 vcl/workben/localestub/localedata_en_ZM.cxx create mode 100644 vcl/workben/localestub/localedata_en_ZW.cxx create mode 100644 vcl/workben/localestub/localestub.cxx create mode 100644 vcl/workben/lwpfuzzer.cxx create mode 100644 vcl/workben/lwpfuzzer.options create mode 100644 vcl/workben/metfuzzer.cxx create mode 100644 vcl/workben/metfuzzer.options create mode 100644 vcl/workben/mmlfuzzer.cxx create mode 100644 vcl/workben/mmlfuzzer.options create mode 100644 vcl/workben/mtfdemo.cxx create mode 100644 vcl/workben/mtpfuzzer.cxx create mode 100644 vcl/workben/mtpfuzzer.options create mode 100644 vcl/workben/olefuzzer.cxx create mode 100644 vcl/workben/olefuzzer.options create mode 100644 vcl/workben/pcdfuzzer.cxx create mode 100644 vcl/workben/pcdfuzzer.options create mode 100644 vcl/workben/pctfuzzer.cxx create mode 100644 vcl/workben/pctfuzzer.options create mode 100644 vcl/workben/pcxfuzzer.cxx create mode 100644 vcl/workben/pcxfuzzer.options create mode 100644 vcl/workben/pngfuzzer.cxx create mode 100644 vcl/workben/pngfuzzer.options create mode 100644 vcl/workben/ppmfuzzer.cxx create mode 100644 vcl/workben/ppmfuzzer.options create mode 100644 vcl/workben/pptfuzzer.cxx create mode 100644 vcl/workben/pptfuzzer.options create mode 100644 vcl/workben/pptxfuzzer.cxx create mode 100644 vcl/workben/pptxfuzzer.options create mode 100644 vcl/workben/psdfuzzer.cxx create mode 100644 vcl/workben/psdfuzzer.options create mode 100644 vcl/workben/qpwfuzzer.cxx create mode 100644 vcl/workben/qpwfuzzer.options create mode 100644 vcl/workben/rasfuzzer.cxx create mode 100644 vcl/workben/rasfuzzer.options create mode 100644 vcl/workben/rtffuzzer.cxx create mode 100644 vcl/workben/rtffuzzer.options create mode 100644 vcl/workben/scrtffuzzer.cxx create mode 100644 vcl/workben/scrtffuzzer.options create mode 100644 vcl/workben/sftfuzzer.cxx create mode 100644 vcl/workben/sftfuzzer.options create mode 100644 vcl/workben/slkfuzzer.cxx create mode 100644 vcl/workben/slkfuzzer.options create mode 100644 vcl/workben/svdem.cxx create mode 100644 vcl/workben/svmfuzzer.cxx create mode 100644 vcl/workben/svmfuzzer.options create mode 100644 vcl/workben/svpclient.cxx create mode 100644 vcl/workben/svptest.cxx create mode 100644 vcl/workben/tgafuzzer.cxx create mode 100644 vcl/workben/tgafuzzer.options create mode 100644 vcl/workben/tiffuzzer.cxx create mode 100644 vcl/workben/tiffuzzer.options create mode 100644 vcl/workben/vcldemo.cxx create mode 100644 vcl/workben/wksfuzzer.cxx create mode 100644 vcl/workben/wksfuzzer.options create mode 100644 vcl/workben/wmffuzzer.cxx create mode 100644 vcl/workben/wmffuzzer.options create mode 100644 vcl/workben/ww2fuzzer.cxx create mode 100644 vcl/workben/ww2fuzzer.options create mode 100644 vcl/workben/ww6fuzzer.cxx create mode 100644 vcl/workben/ww6fuzzer.options create mode 100644 vcl/workben/ww8fuzzer.cxx create mode 100644 vcl/workben/ww8fuzzer.options create mode 100644 vcl/workben/xbmfuzzer.cxx create mode 100644 vcl/workben/xbmfuzzer.options create mode 100644 vcl/workben/xlsfuzzer.cxx create mode 100644 vcl/workben/xlsfuzzer.options create mode 100644 vcl/workben/xlsxfuzzer.cxx create mode 100644 vcl/workben/xlsxfuzzer.options create mode 100644 vcl/workben/xpmfuzzer.cxx create mode 100644 vcl/workben/xpmfuzzer.options (limited to 'vcl') diff --git a/vcl/AllLangMoTarget_vcl.mk b/vcl/AllLangMoTarget_vcl.mk new file mode 100644 index 000000000..784cbe5cf --- /dev/null +++ b/vcl/AllLangMoTarget_vcl.mk @@ -0,0 +1,11 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,vcl)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_apitests.mk b/vcl/CppunitTest_vcl_apitests.mk new file mode 100644 index 000000000..83c618b06 --- /dev/null +++ b/vcl/CppunitTest_vcl_apitests.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_apitests)) + +$(eval $(call gb_CppunitTest_set_include,vcl_apitests,\ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_apitests, \ + vcl/qa/api/XGraphicTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_apitests,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_apitests, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_api,vcl_apitests,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_apitests)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_apitests)) +$(eval $(call gb_CppunitTest_use_configuration,vcl_apitests)) + +$(eval $(call gb_CppunitTest_use_components,vcl_apitests,\ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + filter/source/config/cache/filterconfig1 \ + filter/source/storagefilterdetect/storagefd \ + i18npool/util/i18npool \ + package/source/xstor/xstor \ + package/util/package2 \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svtools/util/svt \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + uui/util/uui \ + vcl/vcl.common \ +)) + + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_app_test.mk b/vcl/CppunitTest_vcl_app_test.mk new file mode 100644 index 000000000..9ee43d5a3 --- /dev/null +++ b/vcl/CppunitTest_vcl_app_test.mk @@ -0,0 +1,32 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_app_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_app_test, \ + vcl/qa/cppunit/app/test_IconThemeInfo \ + vcl/qa/cppunit/app/test_IconThemeScanner \ + vcl/qa/cppunit/app/test_IconThemeSelector \ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_app_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_app_test, \ + sal \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_app_test, \ + boost_headers \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_backend_test.mk b/vcl/CppunitTest_vcl_backend_test.mk new file mode 100644 index 000000000..5a8862240 --- /dev/null +++ b/vcl/CppunitTest_vcl_backend_test.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_backend_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_backend_test, \ + vcl/qa/cppunit/BackendTest \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_backend_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_backend_test)) +$(eval $(call gb_CppunitTest_use_ure,vcl_backend_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_backend_test)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_backend_test,\ + boost_headers\ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_backend_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_components,vcl_backend_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_backend_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_bitmap_render_test.mk b/vcl/CppunitTest_vcl_bitmap_render_test.mk new file mode 100644 index 000000000..3af9c9faf --- /dev/null +++ b/vcl/CppunitTest_vcl_bitmap_render_test.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_bitmap_render_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_bitmap_render_test, \ + vcl/qa/cppunit/bitmaprender/BitmapRenderTest \ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_bitmap_render_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_bitmap_render_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_bitmap_render_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_bitmap_render_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_bitmap_render_test)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_bitmap_render_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_components,vcl_bitmap_render_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_bitmap_render_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_bitmap_test.mk b/vcl/CppunitTest_vcl_bitmap_test.mk new file mode 100644 index 000000000..dca63852a --- /dev/null +++ b/vcl/CppunitTest_vcl_bitmap_test.mk @@ -0,0 +1,64 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_bitmap_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_bitmap_test, \ + vcl/qa/cppunit/BitmapTest \ + vcl/qa/cppunit/BitmapExTest \ + vcl/qa/cppunit/bitmapcolor \ + vcl/qa/cppunit/ScanlineToolsTest \ + vcl/qa/cppunit/BitmapScaleTest \ + vcl/qa/cppunit/BitmapFilterTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_bitmap_test,\ + boost_headers \ + glm_headers \ +)) +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_CppunitTest_use_externals,vcl_bitmap_test,\ + epoxy \ + )) +endif + +$(eval $(call gb_CppunitTest_set_include,vcl_bitmap_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_bitmap_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_bitmap_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_bitmap_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_bitmap_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_bitmap_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + unotools/util/utl \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_bitmap_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_bitmapprocessor_test.mk b/vcl/CppunitTest_vcl_bitmapprocessor_test.mk new file mode 100644 index 000000000..6bdffa9d4 --- /dev/null +++ b/vcl/CppunitTest_vcl_bitmapprocessor_test.mk @@ -0,0 +1,55 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_bitmapprocessor_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_bitmapprocessor_test, \ + vcl/qa/cppunit/BitmapProcessorTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_bitmapprocessor_test,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_bitmapprocessor_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_bitmapprocessor_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_api,vcl_bitmapprocessor_test,\ + udkapi \ + offapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_bitmapprocessor_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_bitmapprocessor_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_bitmapprocessor_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + unotools/util/utl \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_bitmapprocessor_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_blocklistparser_test.mk b/vcl/CppunitTest_vcl_blocklistparser_test.mk new file mode 100644 index 000000000..b585382b4 --- /dev/null +++ b/vcl/CppunitTest_vcl_blocklistparser_test.mk @@ -0,0 +1,45 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_blocklistparser_test)) + +$(eval $(call gb_CppunitTest_set_include,vcl_blocklistparser_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_blocklistparser_test, \ + vcl/qa/cppunit/blocklistparsertest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_blocklistparser_test,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_blocklistparser_test, \ + sal \ + test \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_blocklistparser_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_blocklistparser_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_blocklistparser_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_blocklistparser_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_blocklistparser_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_complextext.mk b/vcl/CppunitTest_vcl_complextext.mk new file mode 100644 index 000000000..540110af9 --- /dev/null +++ b/vcl/CppunitTest_vcl_complextext.mk @@ -0,0 +1,55 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_complextext)) + +$(eval $(call gb_CppunitTest_set_include,vcl_complextext,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_complextext, \ + vcl/qa/cppunit/canvasbitmaptest \ + vcl/qa/cppunit/complextext \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_complextext,\ + boost_headers \ + harfbuzz \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_complextext, \ + comphelper \ + cppu \ + cppuhelper \ + i18nlangtag \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_complextext)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_complextext)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_complextext)) + +$(eval $(call gb_CppunitTest_use_components,vcl_complextext,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_complextext)) + +$(eval $(call gb_CppunitTest_use_more_fonts,vcl_complextext)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_dialogs_test.mk b/vcl/CppunitTest_vcl_dialogs_test.mk new file mode 100644 index 000000000..a602b4270 --- /dev/null +++ b/vcl/CppunitTest_vcl_dialogs_test.mk @@ -0,0 +1,68 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitScreenShot,vcl_dialogs_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_dialogs_test, \ + vcl/qa/unit/vcl-dialogs-test \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_dialogs_test)) + +$(eval $(call gb_CppunitTest_set_include,desktop_dialogs_test,\ + -I$(SRCDIR)/vcl/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_dialogs_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + i18nlangtag \ + i18nutil \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sfx \ + sot \ + svl \ + svt \ + test \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_external,vcl_dialogs_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_dialogs_test)) +$(eval $(call gb_CppunitTest_use_vcl_non_headless_with_windows,vcl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_rdb,vcl_dialogs_test,services)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,vcl_dialogs_test,\ + vcl \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_errorhandler.mk b/vcl/CppunitTest_vcl_errorhandler.mk new file mode 100644 index 000000000..00857fff0 --- /dev/null +++ b/vcl/CppunitTest_vcl_errorhandler.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_errorhandler)) + +$(eval $(call gb_CppunitTest_set_include,vcl_errorhandler,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_errorhandler, \ + vcl/qa/cppunit/errorhandler \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_errorhandler,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_errorhandler, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_errorhandler)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_errorhandler)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_errorhandler)) + +$(eval $(call gb_CppunitTest_use_components,vcl_errorhandler,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_errorhandler)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_filter_ipdf.mk b/vcl/CppunitTest_vcl_filter_ipdf.mk new file mode 100644 index 000000000..403836ac7 --- /dev/null +++ b/vcl/CppunitTest_vcl_filter_ipdf.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_filter_ipdf)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_filter_ipdf,\ + boost_headers \ + pdfium \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_filter_ipdf, \ + vcl/qa/cppunit/filter/ipdf/ipdf \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_filter_ipdf, \ + comphelper \ + cppu \ + sal \ + sfx \ + svx \ + test \ + tl \ + unotest \ + utl \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_filter_ipdf)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_filter_ipdf)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_filter_ipdf)) + +$(eval $(call gb_CppunitTest_use_rdb,vcl_filter_ipdf,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,vcl_filter_ipdf,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_filter_ipdf)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_filters_test.mk b/vcl/CppunitTest_vcl_filters_test.mk new file mode 100644 index 000000000..03a423233 --- /dev/null +++ b/vcl/CppunitTest_vcl_filters_test.mk @@ -0,0 +1,53 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_filters_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_filters_test, \ + vcl/qa/cppunit/graphicfilter/filters-test \ +)) + +ifeq ($(DISABLE_CVE_TESTS),TRUE) +$(eval $(call gb_CppunitTest_add_defs,vcl_filters_test,\ + -DDISABLE_CVE_TESTS \ +)) +endif + +$(eval $(call gb_CppunitTest_use_external,vcl_filters_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_filters_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + emfio \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_filters_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_filters_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_filters_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_filters_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + uui/util/uui \ + emfio/emfio \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_filters_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_font.mk b/vcl/CppunitTest_vcl_font.mk new file mode 100644 index 000000000..8b66a989f --- /dev/null +++ b/vcl/CppunitTest_vcl_font.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_font)) + +$(eval $(call gb_CppunitTest_set_include,vcl_font,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_font, \ + vcl/qa/cppunit/font \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_font,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_font, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_font)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_font)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_font)) + +$(eval $(call gb_CppunitTest_use_components,vcl_font,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_font)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_fontcharmap.mk b/vcl/CppunitTest_vcl_fontcharmap.mk new file mode 100644 index 000000000..0c596bf8d --- /dev/null +++ b/vcl/CppunitTest_vcl_fontcharmap.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_fontcharmap)) + +$(eval $(call gb_CppunitTest_set_include,vcl_fontcharmap,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_fontcharmap, \ + vcl/qa/cppunit/fontcharmap \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_fontcharmap,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_fontcharmap, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_fontcharmap)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_fontcharmap)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_fontcharmap)) + +$(eval $(call gb_CppunitTest_use_components,vcl_fontcharmap,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_fontcharmap)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_fontfeature.mk b/vcl/CppunitTest_vcl_fontfeature.mk new file mode 100644 index 000000000..07a1b319e --- /dev/null +++ b/vcl/CppunitTest_vcl_fontfeature.mk @@ -0,0 +1,51 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_fontfeature)) + +$(eval $(call gb_CppunitTest_set_include,vcl_fontfeature,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_fontfeature, \ + vcl/qa/cppunit/FontFeatureTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_fontfeature,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_fontfeature, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_fontfeature)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_fontfeature)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_fontfeature)) + +$(eval $(call gb_CppunitTest_use_components,vcl_fontfeature,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_fontfeature)) + +$(eval $(call gb_CppunitTest_use_more_fonts,vcl_fontfeature)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_fontmetric.mk b/vcl/CppunitTest_vcl_fontmetric.mk new file mode 100644 index 000000000..5496a75c1 --- /dev/null +++ b/vcl/CppunitTest_vcl_fontmetric.mk @@ -0,0 +1,55 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_fontmetric)) + +$(eval $(call gb_CppunitTest_set_include,vcl_fontmetric,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_fontmetric, \ + vcl/qa/cppunit/fontmetric \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_fontmetric,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_fontmetric, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_fontmetric)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_fontmetric)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_fontmetric)) + +$(eval $(call gb_CppunitTest_use_components,vcl_fontmetric,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_fontmetric)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_fontmetric,\ + harfbuzz \ +)) + +$(eval $(call gb_CppunitTest_use_more_fonts,vcl_fontmetric)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_gen.mk b/vcl/CppunitTest_vcl_gen.mk new file mode 100644 index 000000000..d4f701782 --- /dev/null +++ b/vcl/CppunitTest_vcl_gen.mk @@ -0,0 +1,43 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_gen)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_gen, \ + vcl/qa/cppunit/gen/gen \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_gen, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + sfx \ + subsequenttest \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_external,vcl_gen,boost_headers)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_gen)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_gen)) +$(eval $(call gb_CppunitTest_use_vcl_non_headless,vcl_gen)) + +$(eval $(call gb_CppunitTest_use_rdb,vcl_gen,services)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_gen)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_graphic_test.mk b/vcl/CppunitTest_vcl_graphic_test.mk new file mode 100644 index 000000000..353d054e1 --- /dev/null +++ b/vcl/CppunitTest_vcl_graphic_test.mk @@ -0,0 +1,57 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_graphic_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_graphic_test, \ + vcl/qa/cppunit/GraphicTest \ + vcl/qa/cppunit/GraphicDescriptorTest \ + vcl/qa/cppunit/GraphicFormatDetectorTest \ + vcl/qa/cppunit/GraphicNativeMetadataTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_graphic_test,\ + boost_headers \ + glm_headers \ +)) +ifeq ($(TLS),NSS) +$(eval $(call gb_CppunitTest_use_externals,vcl_graphic_test,\ + plc4 \ + nss3 \ +)) +endif + +$(eval $(call gb_CppunitTest_set_include,vcl_graphic_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_graphic_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_graphic_test)) +$(eval $(call gb_CppunitTest_use_ure,vcl_graphic_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_graphic_test)) +$(eval $(call gb_CppunitTest_use_rdb,vcl_graphic_test,services)) +$(eval $(call gb_CppunitTest_use_configuration,vcl_graphic_test)) + +# we need to explicitly depend on Library_gie because it's dynamically loaded for .gif +$(call gb_CppunitTest_get_target,vcl_graphic_test) : $(call gb_Library_get_target,gie) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_jpeg_read_write_test.mk b/vcl/CppunitTest_vcl_jpeg_read_write_test.mk new file mode 100644 index 000000000..88385872b --- /dev/null +++ b/vcl/CppunitTest_vcl_jpeg_read_write_test.mk @@ -0,0 +1,51 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_jpeg_read_write_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_jpeg_read_write_test, \ + vcl/qa/cppunit/jpeg/JpegReaderTest \ + vcl/qa/cppunit/jpeg/JpegWriterTest \ +)) + +$(eval $(call gb_CppunitTest_use_external,vcl_jpeg_read_write_test,boost_headers)) + +$(eval $(call gb_CppunitTest_set_include,vcl_jpeg_read_write_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_jpeg_read_write_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_jpeg_read_write_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_jpeg_read_write_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_jpeg_read_write_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_jpeg_read_write_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + uui/util/uui \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_jpeg_read_write_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_lifecycle.mk b/vcl/CppunitTest_vcl_lifecycle.mk new file mode 100644 index 000000000..4e8895013 --- /dev/null +++ b/vcl/CppunitTest_vcl_lifecycle.mk @@ -0,0 +1,60 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_lifecycle)) + +$(eval $(call gb_CppunitTest_set_include,vcl_lifecycle,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_lifecycle, \ + vcl/qa/cppunit/lifecycle \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_lifecycle,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_lifecycle, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tk \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_add_defs,vcl_lifecycle,\ + -DVCL_INTERNALS \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_lifecycle)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_lifecycle)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_lifecycle)) + +$(eval $(call gb_CppunitTest_use_components,vcl_lifecycle,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + framework/util/fwk \ + sfx2/util/sfx \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_lifecycle)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,vcl_lifecycle, \ + vcl \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_mnemonic.mk b/vcl/CppunitTest_vcl_mnemonic.mk new file mode 100644 index 000000000..15dc99e8f --- /dev/null +++ b/vcl/CppunitTest_vcl_mnemonic.mk @@ -0,0 +1,49 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_mnemonic)) + +$(eval $(call gb_CppunitTest_set_include,vcl_mnemonic,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_mnemonic, \ + vcl/qa/cppunit/mnemonic \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_mnemonic,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_mnemonic, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + tk \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_mnemonic)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_mnemonic)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_mnemonic)) + +$(eval $(call gb_CppunitTest_use_components,vcl_mnemonic,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_mnemonic)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_outdev.mk b/vcl/CppunitTest_vcl_outdev.mk new file mode 100644 index 000000000..65fd6b5fa --- /dev/null +++ b/vcl/CppunitTest_vcl_outdev.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_outdev)) + +$(eval $(call gb_CppunitTest_set_include,vcl_outdev,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/source/window \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_outdev, \ + vcl/qa/cppunit/outdev \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_outdev,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_outdev, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_outdev)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_outdev)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_outdev)) + +$(eval $(call gb_CppunitTest_use_components,vcl_outdev,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_outdev)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_pdfexport.mk b/vcl/CppunitTest_vcl_pdfexport.mk new file mode 100644 index 000000000..2721d15e4 --- /dev/null +++ b/vcl/CppunitTest_vcl_pdfexport.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_pdfexport)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_pdfexport, \ + vcl/qa/cppunit/pdfexport/pdfexport \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_pdfexport)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_pdfexport, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + test \ + unotest \ + utl \ + tl \ + vcl \ + xmlsecurity \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_pdfexport, \ + boost_headers \ + $(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_pdfexport)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_pdfexport)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_pdfexport)) + +$(eval $(call gb_CppunitTest_use_rdb,vcl_pdfexport,services)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_pdfexport)) + +$(eval $(call gb_CppunitTest_use_more_fonts,vcl_pdfexport)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_png_test.mk b/vcl/CppunitTest_vcl_png_test.mk new file mode 100644 index 000000000..fc513eaec --- /dev/null +++ b/vcl/CppunitTest_vcl_png_test.mk @@ -0,0 +1,54 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_png_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_png_test, \ + vcl/qa/cppunit/png/PngFilterTest \ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_png_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_external,vcl_png_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_png_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ + $(gb_UWINAPI) \ +)) + +$(eval $(call gb_CppunitTest_use_api,vcl_png_test,\ + udkapi \ + offapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_png_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_png_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_png_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + unotools/util/utl \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_png_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_svm_test.mk b/vcl/CppunitTest_vcl_svm_test.mk new file mode 100644 index 000000000..92b4dbaaf --- /dev/null +++ b/vcl/CppunitTest_vcl_svm_test.mk @@ -0,0 +1,59 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_svm_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_svm_test, \ + vcl/qa/cppunit/svm/svmtest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_svm_test,\ + boost_headers \ + libxml2 \ +)) +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_CppunitTest_use_externals,vcl_svm_test,\ + epoxy \ + )) +endif + + +$(eval $(call gb_CppunitTest_set_include,vcl_svm_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_svm_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_svm_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_svm_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_svm_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_svm_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + unotools/util/utl \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_svm_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_timer.mk b/vcl/CppunitTest_vcl_timer.mk new file mode 100644 index 000000000..a89e4e070 --- /dev/null +++ b/vcl/CppunitTest_vcl_timer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_timer)) + +$(eval $(call gb_CppunitTest_set_include,vcl_timer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_timer, \ + vcl/qa/cppunit/timer \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_timer,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_timer, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + salhelper \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_timer)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_timer)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_timer)) + +$(eval $(call gb_CppunitTest_use_components,vcl_timer,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_timer)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_type_serializer_test.mk b/vcl/CppunitTest_vcl_type_serializer_test.mk new file mode 100644 index 000000000..ac668da41 --- /dev/null +++ b/vcl/CppunitTest_vcl_type_serializer_test.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_type_serializer_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_type_serializer_test, \ + vcl/qa/cppunit/TypeSerializerTest \ +)) + +$(eval $(call gb_CppunitTest_use_external,vcl_type_serializer_test,boost_headers)) +ifeq ($(TLS),NSS) +$(eval $(call gb_CppunitTest_use_externals,vcl_type_serializer_test,\ + plc4 \ + nss3 \ +)) +endif + +$(eval $(call gb_CppunitTest_set_include,vcl_type_serializer_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_type_serializer_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_type_serializer_test)) +$(eval $(call gb_CppunitTest_use_rdb,vcl_type_serializer_test,services)) +$(eval $(call gb_CppunitTest_use_ure,vcl_type_serializer_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_type_serializer_test)) +$(eval $(call gb_CppunitTest_use_configuration,vcl_type_serializer_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CppunitTest_vcl_widget_definition_reader_test.mk b/vcl/CppunitTest_vcl_widget_definition_reader_test.mk new file mode 100644 index 000000000..a7d77312c --- /dev/null +++ b/vcl/CppunitTest_vcl_widget_definition_reader_test.mk @@ -0,0 +1,52 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,vcl_widget_definition_reader_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,vcl_widget_definition_reader_test, \ + vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest \ +)) + +$(eval $(call gb_CppunitTest_use_externals,vcl_widget_definition_reader_test,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_set_include,vcl_widget_definition_reader_test,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,vcl_widget_definition_reader_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + utl \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,vcl_widget_definition_reader_test)) + +$(eval $(call gb_CppunitTest_use_ure,vcl_widget_definition_reader_test)) +$(eval $(call gb_CppunitTest_use_vcl,vcl_widget_definition_reader_test)) + +$(eval $(call gb_CppunitTest_use_components,vcl_widget_definition_reader_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ + unotools/util/utl \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,vcl_widget_definition_reader_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_gtk3_kde5_moc.mk b/vcl/CustomTarget_gtk3_kde5_moc.mk new file mode 100644 index 000000000..06f28de31 --- /dev/null +++ b/vcl/CustomTarget_gtk3_kde5_moc.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/unx/gtk3_kde5)) + +$(call gb_CustomTarget_get_target,vcl/unx/gtk3_kde5) : \ + $(call gb_CustomTarget_get_workdir,vcl/unx/gtk3_kde5)/kde5_filepicker.moc \ + $(call gb_CustomTarget_get_workdir,vcl/unx/gtk3_kde5)/kde5_filepicker_ipc.moc \ + +$(call gb_CustomTarget_get_workdir,vcl/unx/gtk3_kde5)/%.moc : \ + $(SRCDIR)/vcl/unx/gtk3_kde5/%.hxx \ + | $(call gb_CustomTarget_get_workdir,vcl/unx/gtk3_kde5)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MOC,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),MOC) + $(MOC5) $< -o $@ + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),MOC) + +# vim: set noet sw=4: diff --git a/vcl/CustomTarget_kf5_moc.mk b/vcl/CustomTarget_kf5_moc.mk new file mode 100644 index 000000000..96f84a937 --- /dev/null +++ b/vcl/CustomTarget_kf5_moc.mk @@ -0,0 +1,23 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/unx/kf5)) + +$(call gb_CustomTarget_get_target,vcl/unx/kf5) : \ + $(call gb_CustomTarget_get_workdir,vcl/unx/kf5)/KF5FilePicker.moc + +$(call gb_CustomTarget_get_workdir,vcl/unx/kf5)/%.moc : \ + $(SRCDIR)/vcl/unx/kf5/%.hxx \ + | $(call gb_CustomTarget_get_workdir,vcl/unx/kf5)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MOC,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),MOC) + $(MOC5) $< -o $@ + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),MOC) + +# vim: set noet sw=4: diff --git a/vcl/CustomTarget_nativecalc.mk b/vcl/CustomTarget_nativecalc.mk new file mode 100644 index 000000000..1c6804082 --- /dev/null +++ b/vcl/CustomTarget_nativecalc.mk @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/workben)) + +fuzzer_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python) + +fuzzer_Native_cxx=$(call gb_CustomTarget_get_workdir,vcl/workben)/native-calc.cxx + +$(fuzzer_Native_cxx): $(SRCDIR)/solenv/bin/native-code.py | $(call gb_CustomTarget_get_workdir,vcl/workben)/.dir + $(call gb_Helper_abbreviate_dirs, $(fuzzer_PYTHONCOMMAND) $(SRCDIR)/solenv/bin/native-code.py -g core -g calc) > $@ + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_nativecore.mk b/vcl/CustomTarget_nativecore.mk new file mode 100644 index 000000000..964e7af1a --- /dev/null +++ b/vcl/CustomTarget_nativecore.mk @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/workben)) + +fuzzer_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python) + +fuzzer_Native_cxx=$(call gb_CustomTarget_get_workdir,vcl/workben)/native-core.cxx + +$(fuzzer_Native_cxx): $(SRCDIR)/solenv/bin/native-code.py | $(call gb_CustomTarget_get_workdir,vcl/workben)/.dir + $(call gb_Helper_abbreviate_dirs, $(fuzzer_PYTHONCOMMAND) $(SRCDIR)/solenv/bin/native-code.py -g core) > $@ + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_nativedraw.mk b/vcl/CustomTarget_nativedraw.mk new file mode 100644 index 000000000..513bf564b --- /dev/null +++ b/vcl/CustomTarget_nativedraw.mk @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/workben)) + +fuzzer_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python) + +fuzzer_Native_cxx=$(call gb_CustomTarget_get_workdir,vcl/workben)/native-draw.cxx + +$(fuzzer_Native_cxx): $(SRCDIR)/solenv/bin/native-code.py | $(call gb_CustomTarget_get_workdir,vcl/workben)/.dir + $(call gb_Helper_abbreviate_dirs, $(fuzzer_PYTHONCOMMAND) $(SRCDIR)/solenv/bin/native-code.py -g core -g draw) > $@ + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_nativemath.mk b/vcl/CustomTarget_nativemath.mk new file mode 100644 index 000000000..7465378c1 --- /dev/null +++ b/vcl/CustomTarget_nativemath.mk @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/workben)) + +fuzzer_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python) + +fuzzer_Native_cxx=$(call gb_CustomTarget_get_workdir,vcl/workben)/native-math.cxx + +$(fuzzer_Native_cxx): $(SRCDIR)/solenv/bin/native-code.py | $(call gb_CustomTarget_get_workdir,vcl/workben)/.dir + $(call gb_Helper_abbreviate_dirs, $(fuzzer_PYTHONCOMMAND) $(SRCDIR)/solenv/bin/native-code.py -g core -g math) > $@ + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_nativewriter.mk b/vcl/CustomTarget_nativewriter.mk new file mode 100644 index 000000000..c396f0f5d --- /dev/null +++ b/vcl/CustomTarget_nativewriter.mk @@ -0,0 +1,18 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/workben)) + +fuzzer_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python) + +fuzzer_Native_cxx=$(call gb_CustomTarget_get_workdir,vcl/workben)/native-writer.cxx + +$(fuzzer_Native_cxx): $(SRCDIR)/solenv/bin/native-code.py | $(call gb_CustomTarget_get_workdir,vcl/workben)/.dir + $(call gb_Helper_abbreviate_dirs, $(fuzzer_PYTHONCOMMAND) $(SRCDIR)/solenv/bin/native-code.py -g core -g writer) > $@ + +# vim: set noet sw=4 ts=4: diff --git a/vcl/CustomTarget_qt5_moc.mk b/vcl/CustomTarget_qt5_moc.mk new file mode 100644 index 000000000..87caee8d9 --- /dev/null +++ b/vcl/CustomTarget_qt5_moc.mk @@ -0,0 +1,33 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CustomTarget_CustomTarget,vcl/qt5)) + +$(call gb_CustomTarget_get_target,vcl/qt5) : \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5AccessibleWidget.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Clipboard.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5FilePicker.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Frame.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Instance.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5MainWindow.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Menu.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Object.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Timer.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5Widget.moc \ + $(call gb_CustomTarget_get_workdir,vcl/qt5)/Qt5XAccessible.moc \ + +$(call gb_CustomTarget_get_workdir,vcl/qt5)/%.moc : \ + $(SRCDIR)/vcl/inc/qt5/%.hxx \ + | $(call gb_CustomTarget_get_workdir,vcl/qt5)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),MOC,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),MOC) + $(MOC5) $< -o $@ + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),MOC) + +# vim: set noet sw=4: diff --git a/vcl/Executable_602fuzzer.mk b/vcl/Executable_602fuzzer.mk new file mode 100644 index 000000000..d18a9a5c9 --- /dev/null +++ b/vcl/Executable_602fuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,602fuzzer)) + +$(eval $(call gb_Executable_use_api,602fuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,602fuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,602fuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,602fuzzer,\ + t602filter \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,602fuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,602fuzzer,\ + vcl/workben/602fuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,602fuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_bmpfuzzer.mk b/vcl/Executable_bmpfuzzer.mk new file mode 100644 index 000000000..da22f2f3b --- /dev/null +++ b/vcl/Executable_bmpfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,bmpfuzzer)) + +$(eval $(call gb_Executable_use_api,bmpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,bmpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,bmpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,bmpfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,bmpfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,bmpfuzzer,\ + vcl/workben/bmpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,bmpfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_cgmfuzzer.mk b/vcl/Executable_cgmfuzzer.mk new file mode 100644 index 000000000..f7cb91520 --- /dev/null +++ b/vcl/Executable_cgmfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,cgmfuzzer)) + +$(eval $(call gb_Executable_use_api,cgmfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,cgmfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,cgmfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,cgmfuzzer,\ + $(fuzzer_draw_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,cgmfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,cgmfuzzer,\ + vcl/workben/cgmfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,cgmfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_diffuzzer.mk b/vcl/Executable_diffuzzer.mk new file mode 100644 index 000000000..03a05ee7c --- /dev/null +++ b/vcl/Executable_diffuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,diffuzzer)) + +$(eval $(call gb_Executable_use_api,diffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,diffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,diffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,diffuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,diffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,diffuzzer,\ + vcl/workben/diffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,diffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_docxfuzzer.mk b/vcl/Executable_docxfuzzer.mk new file mode 100644 index 000000000..b2634a390 --- /dev/null +++ b/vcl/Executable_docxfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,docxfuzzer)) + +$(eval $(call gb_Executable_use_api,docxfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,docxfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,docxfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,docxfuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,docxfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_writer \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,docxfuzzer,\ + vcl/workben/docxfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,docxfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_dxffuzzer.mk b/vcl/Executable_dxffuzzer.mk new file mode 100644 index 000000000..2b8665466 --- /dev/null +++ b/vcl/Executable_dxffuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,dxffuzzer)) + +$(eval $(call gb_Executable_use_api,dxffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,dxffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,dxffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,dxffuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,dxffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,dxffuzzer,\ + vcl/workben/dxffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,dxffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_epsfuzzer.mk b/vcl/Executable_epsfuzzer.mk new file mode 100644 index 000000000..2851b43ad --- /dev/null +++ b/vcl/Executable_epsfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,epsfuzzer)) + +$(eval $(call gb_Executable_use_api,epsfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,epsfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,epsfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,epsfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,epsfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,epsfuzzer,\ + vcl/workben/epsfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,epsfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_fftester.mk b/vcl/Executable_fftester.mk new file mode 100644 index 000000000..0eaa4e39c --- /dev/null +++ b/vcl/Executable_fftester.mk @@ -0,0 +1,39 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,fftester)) + +$(eval $(call gb_Executable_use_api,fftester,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,fftester,boost_headers)) + +$(eval $(call gb_Executable_set_include,fftester,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,fftester,\ + tl \ + sal \ + utl \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +$(eval $(call gb_Executable_add_exception_objects,fftester,\ + vcl/workben/fftester \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_fodpfuzzer.mk b/vcl/Executable_fodpfuzzer.mk new file mode 100644 index 000000000..776231dcd --- /dev/null +++ b/vcl/Executable_fodpfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,fodpfuzzer)) + +$(eval $(call gb_Executable_use_api,fodpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,fodpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,fodpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,fodpfuzzer,\ + $(fuzzer_draw_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,fodpfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_draw \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,fodpfuzzer,\ + vcl/workben/fodpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,fodpfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_fodsfuzzer.mk b/vcl/Executable_fodsfuzzer.mk new file mode 100644 index 000000000..a60c14eae --- /dev/null +++ b/vcl/Executable_fodsfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,fodsfuzzer)) + +$(eval $(call gb_Executable_use_api,fodsfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,fodsfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,fodsfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,fodsfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,fodsfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_calc \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,fodsfuzzer,\ + vcl/workben/fodsfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,fodsfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_fodtfuzzer.mk b/vcl/Executable_fodtfuzzer.mk new file mode 100644 index 000000000..c9801df6c --- /dev/null +++ b/vcl/Executable_fodtfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,fodtfuzzer)) + +$(eval $(call gb_Executable_use_api,fodtfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,fodtfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,fodtfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,fodtfuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,fodtfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_writer \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,fodtfuzzer,\ + vcl/workben/fodtfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,fodtfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_giffuzzer.mk b/vcl/Executable_giffuzzer.mk new file mode 100644 index 000000000..6d0458cba --- /dev/null +++ b/vcl/Executable_giffuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,giffuzzer)) + +$(eval $(call gb_Executable_use_api,giffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,giffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,giffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,giffuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,giffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,giffuzzer,\ + vcl/workben/giffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,giffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_htmlfuzzer.mk b/vcl/Executable_htmlfuzzer.mk new file mode 100644 index 000000000..9c60941cb --- /dev/null +++ b/vcl/Executable_htmlfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,htmlfuzzer)) + +$(eval $(call gb_Executable_use_api,htmlfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,htmlfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,htmlfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,htmlfuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,htmlfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_writer \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,htmlfuzzer,\ + vcl/workben/htmlfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,htmlfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_hwpfuzzer.mk b/vcl/Executable_hwpfuzzer.mk new file mode 100644 index 000000000..974cfd624 --- /dev/null +++ b/vcl/Executable_hwpfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,hwpfuzzer)) + +$(eval $(call gb_Executable_use_api,hwpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,hwpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,hwpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,hwpfuzzer,\ + hwp \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,hwpfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,hwpfuzzer,\ + vcl/workben/hwpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,hwpfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_icontest.mk b/vcl/Executable_icontest.mk new file mode 100644 index 000000000..78a10ccc6 --- /dev/null +++ b/vcl/Executable_icontest.mk @@ -0,0 +1,67 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,icontest)) + +$(eval $(call gb_Executable_use_externals,icontest,\ + boost_headers \ + glm_headers \ +)) +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_Executable_use_externals,icontest,\ + epoxy \ +)) +endif + +ifeq ($(SYSTEM_GLM),TRUE) +$(eval $(call gb_Executable_add_defs,icontest,\ + -DGLM_ENABLE_EXPERIMENTAL \ +)) +endif + +$(eval $(call gb_Executable_add_defs,icontest,\ + -DVCL_INTERNALS \ +)) + +$(eval $(call gb_Executable_use_api,icontest,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_static_libraries,icontest,\ + vclmain \ +)) + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Executable_add_libs,icontest,\ + -lm $(DLOPEN_LIBS) \ + -lX11 \ +)) + +$(eval $(call gb_Executable_use_static_libraries,icontest,\ + glxtest \ +)) + +endif + +$(eval $(call gb_Executable_use_libraries,icontest,\ + comphelper \ + cppu \ + cppuhelper \ + sal \ + tl \ + ucbhelper \ + vcl \ +)) + +$(eval $(call gb_Executable_add_exception_objects,icontest,\ + vcl/workben/icontest \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_jpgfuzzer.mk b/vcl/Executable_jpgfuzzer.mk new file mode 100644 index 000000000..daa801d45 --- /dev/null +++ b/vcl/Executable_jpgfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,jpgfuzzer)) + +$(eval $(call gb_Executable_use_api,jpgfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,jpgfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,jpgfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,jpgfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,jpgfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,jpgfuzzer,\ + vcl/workben/jpgfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,jpgfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_lo_kde5filepicker.mk b/vcl/Executable_lo_kde5filepicker.mk new file mode 100644 index 000000000..08f6b82ed --- /dev/null +++ b/vcl/Executable_lo_kde5filepicker.mk @@ -0,0 +1,94 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Executable_Executable,lo_kde5filepicker)) + +# FIXME: how to find the moc files automatically?! +$(eval $(call gb_Executable_set_include,lo_kde5filepicker,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(WORKDIR)/CustomTarget/vcl/unx/gtk3_kde5 \ +)) + +$(eval $(call gb_Executable_add_cxxflags,lo_kde5filepicker,\ + $$(INCLUDE) \ + $$(BOOST_CXXFLAGS) \ + $(QT5_CFLAGS) \ + $(KF5_CFLAGS) \ +)) + +$(eval $(call gb_Executable_use_custom_headers,lo_kde5filepicker,\ + officecfg/registry \ +)) + +$(eval $(call gb_Executable_use_sdk_api,lo_kde5filepicker)) + +$(eval $(call gb_Executable_add_libs,lo_kde5filepicker,\ + -lX11 \ + -lXext \ + -lSM \ + -lICE \ +)) + +$(eval $(call gb_Executable_use_libraries,lo_kde5filepicker,\ + vclplug_gen \ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Executable_use_externals,lo_kde5filepicker,\ + boost_headers \ + epoxy \ + kf5 \ + dbus \ +)) + +$(eval $(call gb_Executable_add_libs,lo_kde5filepicker,\ + $(QT5_LIBS) \ + $(KF5_LIBS) \ + $(BOOST_PROCESS_LIB) \ + $(BOOST_FILESYSTEM_LIB) \ +)) + +$(eval $(call gb_Executable_add_exception_objects,lo_kde5filepicker,\ + vcl/unx/gtk3_kde5/kde5_lo_filepicker_main \ + vcl/unx/gtk3_kde5/kde5_filepicker \ + vcl/unx/gtk3_kde5/kde5_filepicker_ipc \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Executable_add_libs,lo_kde5filepicker,\ + -lm \ + -ldl \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_lwpfuzzer.mk b/vcl/Executable_lwpfuzzer.mk new file mode 100644 index 000000000..f5148e125 --- /dev/null +++ b/vcl/Executable_lwpfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,lwpfuzzer)) + +$(eval $(call gb_Executable_use_api,lwpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,lwpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,lwpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,lwpfuzzer,\ + lwpft \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,lwpfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,lwpfuzzer,\ + vcl/workben/lwpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,lwpfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_metfuzzer.mk b/vcl/Executable_metfuzzer.mk new file mode 100644 index 000000000..930277d3b --- /dev/null +++ b/vcl/Executable_metfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,metfuzzer)) + +$(eval $(call gb_Executable_use_api,metfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,metfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,metfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,metfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,metfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,metfuzzer,\ + vcl/workben/metfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,metfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_mmlfuzzer.mk b/vcl/Executable_mmlfuzzer.mk new file mode 100644 index 000000000..b093017a7 --- /dev/null +++ b/vcl/Executable_mmlfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,mmlfuzzer)) + +$(eval $(call gb_Executable_use_api,mmlfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,mmlfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,mmlfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,mmlfuzzer,\ + $(fuzzer_math_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,mmlfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_math \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,mmlfuzzer,\ + vcl/workben/mmlfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,mmlfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_mtfdemo.mk b/vcl/Executable_mtfdemo.mk new file mode 100644 index 000000000..5c4c45165 --- /dev/null +++ b/vcl/Executable_mtfdemo.mk @@ -0,0 +1,54 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,mtfdemo)) + +$(eval $(call gb_Executable_use_api,mtfdemo,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,mtfdemo,boost_headers)) + +$(eval $(call gb_Executable_set_include,mtfdemo,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,mtfdemo,\ + basegfx \ + tl \ + sal \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +$(eval $(call gb_Executable_add_exception_objects,mtfdemo,\ + vcl/workben/mtfdemo \ +)) + +$(eval $(call gb_Executable_use_static_libraries,mtfdemo,\ + vclmain \ +)) + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Executable_add_libs,mtfdemo,\ + -lm $(DLOPEN_LIBS) \ + -lX11 \ +)) + +$(eval $(call gb_Executable_use_static_libraries,mtfdemo,\ + glxtest \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_mtpfuzzer.mk b/vcl/Executable_mtpfuzzer.mk new file mode 100644 index 000000000..73e30b257 --- /dev/null +++ b/vcl/Executable_mtpfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,mtpfuzzer)) + +$(eval $(call gb_Executable_use_api,mtpfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,mtpfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,mtpfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,mtpfuzzer,\ + $(fuzzer_math_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,mtpfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,mtpfuzzer,\ + vcl/workben/mtpfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,mtpfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_olefuzzer.mk b/vcl/Executable_olefuzzer.mk new file mode 100644 index 000000000..4a73d573b --- /dev/null +++ b/vcl/Executable_olefuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,olefuzzer)) + +$(eval $(call gb_Executable_use_api,olefuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,olefuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,olefuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,olefuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,olefuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,olefuzzer,\ + vcl/workben/olefuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,olefuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pcdfuzzer.mk b/vcl/Executable_pcdfuzzer.mk new file mode 100644 index 000000000..65916135e --- /dev/null +++ b/vcl/Executable_pcdfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pcdfuzzer)) + +$(eval $(call gb_Executable_use_api,pcdfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pcdfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pcdfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pcdfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pcdfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pcdfuzzer,\ + vcl/workben/pcdfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pcdfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pctfuzzer.mk b/vcl/Executable_pctfuzzer.mk new file mode 100644 index 000000000..0265fd59d --- /dev/null +++ b/vcl/Executable_pctfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pctfuzzer)) + +$(eval $(call gb_Executable_use_api,pctfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pctfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pctfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pctfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pctfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pctfuzzer,\ + vcl/workben/pctfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pctfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pcxfuzzer.mk b/vcl/Executable_pcxfuzzer.mk new file mode 100644 index 000000000..ad24b43c1 --- /dev/null +++ b/vcl/Executable_pcxfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pcxfuzzer)) + +$(eval $(call gb_Executable_use_api,pcxfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pcxfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pcxfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pcxfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pcxfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pcxfuzzer,\ + vcl/workben/pcxfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pcxfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pngfuzzer.mk b/vcl/Executable_pngfuzzer.mk new file mode 100644 index 000000000..24b9f4897 --- /dev/null +++ b/vcl/Executable_pngfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pngfuzzer)) + +$(eval $(call gb_Executable_use_api,pngfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pngfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pngfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pngfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pngfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pngfuzzer,\ + vcl/workben/pngfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pngfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_ppmfuzzer.mk b/vcl/Executable_ppmfuzzer.mk new file mode 100644 index 000000000..d0909ebba --- /dev/null +++ b/vcl/Executable_ppmfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,ppmfuzzer)) + +$(eval $(call gb_Executable_use_api,ppmfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,ppmfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,ppmfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,ppmfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ppmfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,ppmfuzzer,\ + vcl/workben/ppmfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,ppmfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pptfuzzer.mk b/vcl/Executable_pptfuzzer.mk new file mode 100644 index 000000000..85c8ed3c4 --- /dev/null +++ b/vcl/Executable_pptfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pptfuzzer)) + +$(eval $(call gb_Executable_use_api,pptfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pptfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pptfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pptfuzzer,\ + $(fuzzer_draw_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pptfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pptfuzzer,\ + vcl/workben/pptfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pptfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_pptxfuzzer.mk b/vcl/Executable_pptxfuzzer.mk new file mode 100644 index 000000000..3687a1808 --- /dev/null +++ b/vcl/Executable_pptxfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,pptxfuzzer)) + +$(eval $(call gb_Executable_use_api,pptxfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,pptxfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,pptxfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,pptxfuzzer,\ + $(fuzzer_draw_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,pptxfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_draw \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,pptxfuzzer,\ + vcl/workben/pptxfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,pptxfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_psdfuzzer.mk b/vcl/Executable_psdfuzzer.mk new file mode 100644 index 000000000..e53d3dddb --- /dev/null +++ b/vcl/Executable_psdfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,psdfuzzer)) + +$(eval $(call gb_Executable_use_api,psdfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,psdfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,psdfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,psdfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,psdfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,psdfuzzer,\ + vcl/workben/psdfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,psdfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_qpwfuzzer.mk b/vcl/Executable_qpwfuzzer.mk new file mode 100644 index 000000000..4f8103355 --- /dev/null +++ b/vcl/Executable_qpwfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,qpwfuzzer)) + +$(eval $(call gb_Executable_use_api,qpwfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,qpwfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,qpwfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,qpwfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,qpwfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,qpwfuzzer,\ + vcl/workben/qpwfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,qpwfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_rasfuzzer.mk b/vcl/Executable_rasfuzzer.mk new file mode 100644 index 000000000..7440544c7 --- /dev/null +++ b/vcl/Executable_rasfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,rasfuzzer)) + +$(eval $(call gb_Executable_use_api,rasfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,rasfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,rasfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,rasfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,rasfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,rasfuzzer,\ + vcl/workben/rasfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,rasfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_rtffuzzer.mk b/vcl/Executable_rtffuzzer.mk new file mode 100644 index 000000000..28f0a3afe --- /dev/null +++ b/vcl/Executable_rtffuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,rtffuzzer)) + +$(eval $(call gb_Executable_use_api,rtffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,rtffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,rtffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,rtffuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,rtffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,rtffuzzer,\ + vcl/workben/rtffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,rtffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_scrtffuzzer.mk b/vcl/Executable_scrtffuzzer.mk new file mode 100644 index 000000000..6721092b2 --- /dev/null +++ b/vcl/Executable_scrtffuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,scrtffuzzer)) + +$(eval $(call gb_Executable_use_api,scrtffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,scrtffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,scrtffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,scrtffuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,scrtffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,scrtffuzzer,\ + vcl/workben/scrtffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,scrtffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_sftfuzzer.mk b/vcl/Executable_sftfuzzer.mk new file mode 100644 index 000000000..be2ecff64 --- /dev/null +++ b/vcl/Executable_sftfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,sftfuzzer)) + +$(eval $(call gb_Executable_use_api,sftfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,sftfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,sftfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,sftfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,sftfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,sftfuzzer,\ + vcl/workben/sftfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,sftfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_slkfuzzer.mk b/vcl/Executable_slkfuzzer.mk new file mode 100644 index 000000000..b37cb8f16 --- /dev/null +++ b/vcl/Executable_slkfuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,slkfuzzer)) + +$(eval $(call gb_Executable_use_api,slkfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,slkfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,slkfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,slkfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,slkfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,slkfuzzer,\ + vcl/workben/slkfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,slkfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_svdemo.mk b/vcl/Executable_svdemo.mk new file mode 100644 index 000000000..0a958a286 --- /dev/null +++ b/vcl/Executable_svdemo.mk @@ -0,0 +1,38 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,svdemo)) + +$(eval $(call gb_Executable_use_api,svdemo,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,svdemo,boost_headers)) + +$(eval $(call gb_Executable_set_include,svdemo,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,svdemo,\ + tl \ + sal \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +$(eval $(call gb_Executable_add_exception_objects,svdemo,\ + vcl/workben/svdem \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_svmfuzzer.mk b/vcl/Executable_svmfuzzer.mk new file mode 100644 index 000000000..9d41cc6ed --- /dev/null +++ b/vcl/Executable_svmfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,svmfuzzer)) + +$(eval $(call gb_Executable_use_api,svmfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,svmfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,svmfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,svmfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,svmfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,svmfuzzer,\ + vcl/workben/svmfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,svmfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_svpclient.mk b/vcl/Executable_svpclient.mk new file mode 100644 index 000000000..3d92f2ebc --- /dev/null +++ b/vcl/Executable_svpclient.mk @@ -0,0 +1,42 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,svpclient)) + +$(eval $(call gb_Executable_use_api,svpclient,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,svpclient,boost_headers)) + +$(eval $(call gb_Executable_set_include,svpclient,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,svpclient,\ + tl \ + sal \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +ifeq ($(OS),HAIKU) +$(eval $(call gb_Executable_add_libs,svpclient,-lnetwork)) +endif + +$(eval $(call gb_Executable_add_exception_objects,svpclient,\ + vcl/workben/svpclient \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_svptest.mk b/vcl/Executable_svptest.mk new file mode 100644 index 000000000..c373aa66f --- /dev/null +++ b/vcl/Executable_svptest.mk @@ -0,0 +1,38 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,svptest)) + +$(eval $(call gb_Executable_use_api,svptest,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,svptest,boost_headers)) + +$(eval $(call gb_Executable_set_include,svptest,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,svptest,\ + tl \ + sal \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +$(eval $(call gb_Executable_add_exception_objects,svptest,\ + vcl/workben/svptest \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_tgafuzzer.mk b/vcl/Executable_tgafuzzer.mk new file mode 100644 index 000000000..a53da7c7e --- /dev/null +++ b/vcl/Executable_tgafuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,tgafuzzer)) + +$(eval $(call gb_Executable_use_api,tgafuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,tgafuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,tgafuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,tgafuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,tgafuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,tgafuzzer,\ + vcl/workben/tgafuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,tgafuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_tiffuzzer.mk b/vcl/Executable_tiffuzzer.mk new file mode 100644 index 000000000..1b8103aa0 --- /dev/null +++ b/vcl/Executable_tiffuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,tiffuzzer)) + +$(eval $(call gb_Executable_use_api,tiffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,tiffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,tiffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,tiffuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,tiffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,tiffuzzer,\ + vcl/workben/tiffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,tiffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_ui-previewer.mk b/vcl/Executable_ui-previewer.mk new file mode 100644 index 000000000..bee97cbac --- /dev/null +++ b/vcl/Executable_ui-previewer.mk @@ -0,0 +1,54 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,ui-previewer)) + +$(eval $(call gb_Executable_use_external,ui-previewer,boost_headers)) + +$(eval $(call gb_Executable_use_api,ui-previewer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ui-previewer,\ + vclmain \ +)) + +$(eval $(call gb_Executable_use_libraries,ui-previewer,\ + comphelper \ + cppu \ + cppuhelper \ + sal \ + tl \ + ucbhelper \ + vcl \ +)) + +$(eval $(call gb_Executable_add_exception_objects,ui-previewer,\ + vcl/source/uipreviewer/previewer \ +)) + +$(eval $(call gb_Executable_add_defs,ui-previewer,\ + -DVCL_INTERNALS \ +)) + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Executable_add_libs,ui-previewer,\ + -lm $(DLOPEN_LIBS) \ + -lX11 \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ui-previewer,\ + glxtest \ +)) +endif + +$(eval $(call gb_Executable_add_default_nativeres,ui-previewer)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_vcldemo.mk b/vcl/Executable_vcldemo.mk new file mode 100644 index 000000000..a9a8d195f --- /dev/null +++ b/vcl/Executable_vcldemo.mk @@ -0,0 +1,68 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,vcldemo)) + +$(eval $(call gb_Executable_use_api,vcldemo,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,vcldemo,\ + boost_headers \ + glm_headers \ + harfbuzz \ +)) +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_Executable_use_externals,vcldemo,\ + epoxy \ +)) +endif + +$(eval $(call gb_Executable_add_defs,vcldemo,\ + -DVCL_INTERNALS \ +)) + +$(eval $(call gb_Executable_set_include,vcldemo,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,vcldemo,\ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + tl \ + sal \ + salhelper \ + vcl \ +)) + +$(eval $(call gb_Executable_add_exception_objects,vcldemo,\ + vcl/workben/vcldemo \ +)) + +$(eval $(call gb_Executable_use_static_libraries,vcldemo,\ + vclmain \ +)) + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Executable_add_libs,vcldemo,\ + -lm $(DLOPEN_LIBS) \ + -lX11 \ +)) + +$(eval $(call gb_Executable_use_static_libraries,vcldemo,\ + glxtest \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_visualbackendtest.mk b/vcl/Executable_visualbackendtest.mk new file mode 100644 index 000000000..41c641a5f --- /dev/null +++ b/vcl/Executable_visualbackendtest.mk @@ -0,0 +1,56 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,visualbackendtest)) + +$(eval $(call gb_Executable_use_api,visualbackendtest,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,visualbackendtest,boost_headers)) + +$(eval $(call gb_Executable_set_include,visualbackendtest,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,visualbackendtest,\ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + tl \ + sal \ + salhelper \ + vcl \ +)) + +$(eval $(call gb_Executable_add_exception_objects,visualbackendtest,\ + vcl/backendtest/VisualBackendTest \ +)) + +$(eval $(call gb_Executable_use_static_libraries,visualbackendtest,\ + vclmain \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Executable_add_libs,visualbackendtest,\ + -lm \ + -ldl \ + -lX11 \ +)) + +$(eval $(call gb_Executable_use_static_libraries,visualbackendtest,\ + glxtest \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_wksfuzzer.mk b/vcl/Executable_wksfuzzer.mk new file mode 100644 index 000000000..2c0776888 --- /dev/null +++ b/vcl/Executable_wksfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,wksfuzzer)) + +$(eval $(call gb_Executable_use_api,wksfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,wksfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,wksfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,wksfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,wksfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_calc \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,wksfuzzer,\ + vcl/workben/wksfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,wksfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_wmffuzzer.mk b/vcl/Executable_wmffuzzer.mk new file mode 100644 index 000000000..7e277e0ae --- /dev/null +++ b/vcl/Executable_wmffuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,wmffuzzer)) + +$(eval $(call gb_Executable_use_api,wmffuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,wmffuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,wmffuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,wmffuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,wmffuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,wmffuzzer,\ + vcl/workben/wmffuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,wmffuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_ww2fuzzer.mk b/vcl/Executable_ww2fuzzer.mk new file mode 100644 index 000000000..bd6f95fa3 --- /dev/null +++ b/vcl/Executable_ww2fuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,ww2fuzzer)) + +$(eval $(call gb_Executable_use_api,ww2fuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,ww2fuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,ww2fuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,ww2fuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ww2fuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,ww2fuzzer,\ + vcl/workben/ww2fuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,ww2fuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_ww6fuzzer.mk b/vcl/Executable_ww6fuzzer.mk new file mode 100644 index 000000000..cf540f89e --- /dev/null +++ b/vcl/Executable_ww6fuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,ww6fuzzer)) + +$(eval $(call gb_Executable_use_api,ww6fuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,ww6fuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,ww6fuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,ww6fuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ww6fuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,ww6fuzzer,\ + vcl/workben/ww6fuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,ww6fuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_ww8fuzzer.mk b/vcl/Executable_ww8fuzzer.mk new file mode 100644 index 000000000..62bfd3c53 --- /dev/null +++ b/vcl/Executable_ww8fuzzer.mk @@ -0,0 +1,48 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,ww8fuzzer)) + +$(eval $(call gb_Executable_use_api,ww8fuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,ww8fuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,ww8fuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,ww8fuzzer,\ + $(fuzzer_writer_libraries) \ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,ww8fuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,ww8fuzzer,\ + vcl/workben/ww8fuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,ww8fuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_xbmfuzzer.mk b/vcl/Executable_xbmfuzzer.mk new file mode 100644 index 000000000..fc67b8e8d --- /dev/null +++ b/vcl/Executable_xbmfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,xbmfuzzer)) + +$(eval $(call gb_Executable_use_api,xbmfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,xbmfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,xbmfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,xbmfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,xbmfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,xbmfuzzer,\ + vcl/workben/xbmfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,xbmfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_xlsfuzzer.mk b/vcl/Executable_xlsfuzzer.mk new file mode 100644 index 000000000..d3b2948d6 --- /dev/null +++ b/vcl/Executable_xlsfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,xlsfuzzer)) + +$(eval $(call gb_Executable_use_api,xlsfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,xlsfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,xlsfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,xlsfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,xlsfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_calc \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,xlsfuzzer,\ + vcl/workben/xlsfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,xlsfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_xlsxfuzzer.mk b/vcl/Executable_xlsxfuzzer.mk new file mode 100644 index 000000000..adf33c457 --- /dev/null +++ b/vcl/Executable_xlsxfuzzer.mk @@ -0,0 +1,50 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,xlsxfuzzer)) + +$(eval $(call gb_Executable_use_api,xlsxfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,xlsxfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,xlsxfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,xlsxfuzzer,\ + $(fuzzer_calc_libraries) \ + $(fuzzer_core_libraries) \ + pdffilter \ +)) + +$(eval $(call gb_Executable_use_static_libraries,xlsxfuzzer,\ + findsofficepath \ + ulingu \ + fuzzer_calc \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,xlsxfuzzer,\ + vcl/workben/xlsxfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,xlsxfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_xpmfuzzer.mk b/vcl/Executable_xpmfuzzer.mk new file mode 100644 index 000000000..892d5c962 --- /dev/null +++ b/vcl/Executable_xpmfuzzer.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +include $(SRCDIR)/vcl/commonfuzzer.mk + +$(eval $(call gb_Executable_Executable,xpmfuzzer)) + +$(eval $(call gb_Executable_use_api,xpmfuzzer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_externals,xpmfuzzer,\ + $(fuzzer_externals) \ +)) + +$(eval $(call gb_Executable_set_include,xpmfuzzer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,xpmfuzzer,\ + $(fuzzer_core_libraries) \ +)) + +$(eval $(call gb_Executable_use_static_libraries,xpmfuzzer,\ + findsofficepath \ + ulingu \ + fuzzerstubs \ +)) + +$(eval $(call gb_Executable_add_exception_objects,xpmfuzzer,\ + vcl/workben/xpmfuzzer \ +)) + +$(eval $(call gb_Executable_add_libs,xpmfuzzer,\ + -lFuzzingEngine \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/IwyuFilter_vcl.yaml b/vcl/IwyuFilter_vcl.yaml new file mode 100644 index 000000000..423c06109 --- /dev/null +++ b/vcl/IwyuFilter_vcl.yaml @@ -0,0 +1,128 @@ +--- +assumeFilename: vcl/source/app/svapp.cxx +blacklist: + vcl/inc/salusereventlist.hxx: + # Don't propose hxx -> h change in URE libs + - osl/thread.hxx + vcl/inc/headless/svpgdi.hxx: + # OSL_BIGENDIAN is being checked + - osl/endian.h + vcl/inc/headless/svpinst.hxx: + # Don't propose hxx -> h change in URE libs + - osl/thread.hxx + vcl/inc/opengl/RenderList.hxx: + # Don't replace with impl. details + - glm/glm.hpp + vcl/inc/opengl/VertexUtils.hxx: + # Don't replace with impl. details + - glm/gtx/norm.hpp + vcl/inc/unx/gendata.hxx: + # Don't propose hxx -> h change in URE libs + - osl/socket.hxx + vcl/inc/unx/saldisp.hxx: + # Don't replace with generated header + - epoxy/glx.h + vcl/qa/cppunit/outdev.cxx: + # Needed for direct member access + - basegfx/matrix/b2dhommatrix.hxx + vcl/source/app/salplug.cxx: + # Needed on WIN32 + - salframe.hxx + vcl/source/app/svdata.cxx: + # Needed on WIN32 + - com/sun/star/accessibility/MSAAService.hpp + - salframe.hxx + vcl/source/app/svmain.cxx: + # Needed on WIN32 + - desktop/exithelper.h + vcl/source/components/factory.cxx: + # Actually these are used + - com/sun/star/lang/XMultiServiceFactory.hpp + - com/sun/star/lang/XSingleServiceFactory.hpp + vcl/source/filter/FilterConfigItem.cxx: + # Needed for direct member access + - com/sun/star/task/XStatusIndicator.hpp + vcl/source/filter/ipdf/pdfdocument.cxx: + - comphelper/scopeguard.hxx + # Actually these are used + - com/sun/star/security/XCertificate.hpp + - vector + vcl/source/filter/jpeg/JpegWriter.hxx: + # Needed for direct member access + - vcl/bitmapaccess.hxx + vcl/source/filter/png/pngwrite.cxx: + # Actually these are used + - com/sun/star/beans/PropertyValue.hpp + - com/sun/star/uno/Sequence.hxx + vcl/source/filter/wmf/wmfexternal.cxx: + # Actually these are used + - com/sun/star/beans/PropertyValue.hpp + vcl/source/font/fontselect.cxx: + # Needed on WIN32 + - PhysicalFontFace.hxx + vcl/source/fontsubset/sft.cxx: + # OSL_BIGENDIAN is being checked + - osl/endian.h + # Needed on WIN32 / MAC / IOS + - xlat.hxx + vcl/source/gdi/configsettings.cxx: + # Needed for OSL_DEBUG_LEVEL > 2 + - sal/log.hxx + vcl/source/gdi/salgdilayout.cxx: + # Needed on WIN32 + - desktop/exithelper.h + vcl/source/helper/commandinfoprovider.cxx: + # Actually these are used + - com/sun/star/frame/XFrame.hpp + vcl/source/image/ImageTree.cxx: + # Actually these are used + - com/sun/star/container/XNameAccess.hpp + - com/sun/star/uno/Reference.hxx + vcl/source/treelist/headbar.cxx: + # Actually these are used + - com/sun/star/accessibility/XAccessible.hpp + vcl/source/window/dialog.cxx: + # comphelper::ScopeGuard is actually used + - comphelper/scopeguard.hxx + vcl/source/window/event.cxx: + # comphelper::ScopeGuard is actually used + - comphelper/scopeguard.hxx + vcl/unx/generic/app/saldisp.cxx: + # needed for transitive cursor includes + - unx/x11_cursors/salcursors.h + vcl/unx/generic/gdi/font.cxx: + # Complete type needed for implicit dtor + - vcl/fontcharmap.hxx + vcl/unx/generic/gdi/salbmp.cxx: + # OSL_BIGENDIAN is being checked + - osl/endian.h + vcl/unx/generic/glyphs/freetype_glyphcache.cxx: + # Needed for FreeType header macros + - ft2build.h + vcl/unx/generic/print/genpspgraphics.cxx: + # Complete type needed for implicit dtor + - vcl/fontcharmap.hxx + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker.cxx: + # Actually these are used + - QUrl + - KFileWidget + vcl/unx/gtk3_kde5/kde5_filepicker.cxx: + # Actually these are used + - KWindowSystem + - KFileWidget + - QtCore/QDebug + - QtCore/QUrl + - QtWidgets/QCheckBox + - QtWidgets/QFileDialog + - QtWidgets/QGridLayout + - QtWidgets/QWidget + - QtWidgets/QApplication + vcl/unx/gtk3_kde5/kde5_lo_filepicker_main.cxx: + # Actually these are used + - QApplication + - QCommandLineParser + vcl/unx/gtk3_kde5/kde5_filepicker_ipc.cxx: + # Actually these are used + - QUrl + - QApplication + - QDebug diff --git a/vcl/Library_desktop_detector.mk b/vcl/Library_desktop_detector.mk new file mode 100644 index 000000000..f28ff9078 --- /dev/null +++ b/vcl/Library_desktop_detector.mk @@ -0,0 +1,72 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,desktop_detector)) + +$(eval $(call gb_Library_set_include,desktop_detector,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Library_add_defs,desktop_detector,\ + -DDESKTOP_DETECTOR_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_sdk_api,desktop_detector)) + +$(eval $(call gb_Library_use_libraries,desktop_detector,\ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,desktop_detector,\ + boost_headers \ + icuuc \ +)) + +$(eval $(call gb_Library_add_libs,desktop_detector,\ + -lX11 \ + -lXext \ + -lSM \ + -lICE \ +)) + +$(eval $(call gb_Library_add_exception_objects,desktop_detector,\ + vcl/unx/generic/desktopdetect/desktopdetector \ +)) + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Library_add_libs,desktop_detector,\ + -lm $(DLOPEN_LIBS) \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk new file mode 100644 index 000000000..e12ccf1a6 --- /dev/null +++ b/vcl/Library_vcl.mk @@ -0,0 +1,736 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vcl)) + +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.common)) + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.macosx)) +else ifeq ($(OS),WNT) +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.windows)) +else ifeq ($(OS),ANDROID) +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.android)) +else ifeq ($(OS),iOS) +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.ios)) +else ifeq ($(DISABLE_GUI),TRUE) +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.headless)) +else +$(eval $(call gb_Library_set_componentfile,vcl,vcl/vcl.unx)) +endif + +$(eval $(call gb_Library_set_precompiled_header,vcl,vcl/inc/pch/precompiled_vcl)) + +$(eval $(call gb_Library_set_include,vcl,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Library_add_defs,vcl,\ + -DVCL_DLLIMPLEMENTATION \ + -DDLLIMPLEMENTATION_UITEST \ + -DCUI_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,cui))\" \ + -DDESKTOP_DETECTOR_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,desktop_detector))\" \ + -DTK_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,tk))\" \ +)) + +ifeq ($(SYSTEM_GLM),TRUE) +$(eval $(call gb_Library_add_defs,vcl,\ + -DGLM_ENABLE_EXPERIMENTAL \ +)) +endif + +$(eval $(call gb_Library_use_sdk_api,vcl)) + +$(eval $(call gb_Library_use_custom_headers,vcl,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_externals,vcl,\ + libjpeg \ + libeot \ + libpng \ + $(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \ +)) + +$(eval $(call gb_Library_use_libraries,vcl,\ + $(call gb_Helper_optional,BREAKPAD, \ + crashreport) \ + svl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \ + cppu \ + sal \ + salhelper \ + xmlreader \ +)) + +ifeq ($(ENABLE_JAVA),TRUE) +$(eval $(call gb_Library_use_libraries,vcl,\ + jvmaccess \ +)) +endif + +$(eval $(call gb_Library_use_externals,vcl,\ + boost_headers \ + gio \ + glm_headers \ + graphite \ + harfbuzz \ + icu_headers \ + icuuc \ + lcms2 \ + mdds_headers \ + $(if $(filter SKIA,$(BUILD_TYPE)),skia) \ +)) + +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_Library_use_externals,vcl,\ + epoxy \ + )) +endif + +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/source/animate/Animation \ + vcl/source/animate/AnimationBitmap \ + vcl/source/window/errinf \ + vcl/source/window/settings \ + vcl/source/window/paint \ + vcl/source/window/abstdlg \ + vcl/source/window/accel \ + vcl/source/window/accmgr \ + vcl/source/window/brdwin \ + vcl/source/window/bufferdevice \ + vcl/source/window/accessibility \ + vcl/source/window/legacyaccessibility \ + vcl/source/window/clipping \ + vcl/source/window/stacking \ + vcl/source/window/debug \ + vcl/source/window/globalization \ + vcl/source/window/builder \ + vcl/source/window/commandevent \ + vcl/source/window/cursor \ + vcl/source/window/debugevent \ + vcl/source/window/decoview \ + vcl/source/window/dialog \ + vcl/source/window/dlgctrl \ + vcl/source/window/dndeventdispatcher \ + vcl/source/window/dndlistenercontainer \ + vcl/source/window/dockingarea \ + vcl/source/window/dockmgr \ + vcl/source/window/dockwin \ + vcl/source/window/event \ + vcl/source/window/floatwin \ + vcl/source/window/introwin \ + vcl/source/window/keycod \ + vcl/source/window/keyevent \ + vcl/source/window/layout \ + vcl/source/window/menu \ + vcl/source/window/menubarwindow \ + vcl/source/window/menufloatingwindow \ + vcl/source/window/menuitemlist \ + vcl/source/window/menuwindow \ + vcl/source/window/mnemonic \ + vcl/source/window/mnemonicengine \ + vcl/source/window/mouse \ + vcl/source/window/NotebookBarAddonsMerger \ + vcl/source/window/OptionalBox \ + vcl/source/window/popupmenuwindow \ + vcl/source/window/printdlg \ + vcl/source/window/scrwnd \ + vcl/source/window/seleng \ + vcl/source/window/split \ + vcl/source/window/splitwin \ + vcl/source/window/status \ + vcl/source/window/syschild \ + vcl/source/window/syswin \ + vcl/source/window/tabdlg \ + vcl/source/window/tabpage \ + vcl/source/window/taskpanelist \ + vcl/source/window/toolbox2 \ + vcl/source/window/toolbox \ + vcl/source/window/window2 \ + vcl/source/window/window3 \ + vcl/source/window/window \ + vcl/source/window/winproc \ + vcl/source/window/wrkwin \ + vcl/source/window/EnumContext \ + vcl/source/control/button \ + vcl/source/control/calendar \ + vcl/source/control/combobox \ + vcl/source/control/ctrl \ + vcl/source/control/edit \ + vcl/source/control/field2 \ + vcl/source/control/field \ + vcl/source/control/fixed \ + vcl/source/control/fixedhyper \ + vcl/source/control/hyperlabel \ + vcl/source/control/fmtfield \ + vcl/source/control/InterimItemWindow \ + vcl/source/control/imgctrl \ + vcl/source/control/imivctl1 \ + vcl/source/control/imivctl2 \ + vcl/source/control/ivctrl \ + vcl/source/control/longcurr \ + vcl/source/control/imp_listbox \ + vcl/source/control/listbox \ + vcl/source/control/menubtn \ + vcl/source/control/notebookbar \ + vcl/source/control/quickselectionengine \ + vcl/source/control/prgsbar \ + vcl/source/control/roadmap \ + vcl/source/control/roadmapwizard \ + vcl/source/control/scrbar \ + vcl/source/control/slider \ + vcl/source/control/spinbtn \ + vcl/source/control/spinfld \ + vcl/source/control/tabctrl \ + vcl/source/control/throbber \ + vcl/source/control/wizardmachine \ + vcl/source/edit/vclmedit \ + vcl/source/edit/textdata \ + vcl/source/edit/textdoc \ + vcl/source/edit/texteng \ + vcl/source/edit/textundo \ + vcl/source/edit/textview \ + vcl/source/edit/txtattr \ + vcl/source/edit/xtextedt \ + vcl/source/toolkit/group \ + vcl/source/toolkit/morebtn \ + vcl/source/outdev/outdev \ + vcl/source/outdev/outdevstate \ + vcl/source/outdev/clipping \ + vcl/source/outdev/polygon \ + vcl/source/outdev/transparent \ + vcl/source/outdev/mask \ + vcl/source/outdev/bitmap \ + vcl/source/outdev/font \ + vcl/source/outdev/text \ + vcl/source/outdev/textline \ + vcl/source/outdev/pixel \ + vcl/source/outdev/rect \ + vcl/source/outdev/line \ + vcl/source/outdev/polyline \ + vcl/source/outdev/hatch \ + vcl/source/outdev/gradient \ + vcl/source/outdev/curvedshapes \ + vcl/source/outdev/wallpaper \ + vcl/source/outdev/vclreferencebase \ + vcl/source/outdev/nativecontrols \ + vcl/source/outdev/map \ + vcl/source/treelist/headbar \ + vcl/source/treelist/iconview \ + vcl/source/treelist/iconviewimpl \ + vcl/source/treelist/imap \ + vcl/source/treelist/imap2 \ + vcl/source/treelist/imap3 \ + vcl/source/treelist/inetimg \ + vcl/source/treelist/svtabbx \ + vcl/source/treelist/transfer \ + vcl/source/treelist/transfer2 \ + vcl/source/treelist/viewdataentry \ + vcl/source/treelist/treelist \ + vcl/source/treelist/treelistbox \ + vcl/source/treelist/treelistentry \ + vcl/source/treelist/svimpbox \ + vcl/source/treelist/svlbitm \ + vcl/source/treelist/uiobject \ + vcl/source/gdi/alpha \ + vcl/source/gdi/bitmap3 \ + vcl/source/gdi/bitmapex \ + vcl/source/gdi/bmpacc2 \ + vcl/source/gdi/bmpacc3 \ + vcl/source/gdi/bmpacc \ + vcl/source/gdi/bmpfast \ + vcl/source/gdi/configsettings \ + vcl/source/gdi/cvtgrf \ + vcl/source/gdi/svmconverter \ + vcl/source/gdi/dibtools \ + vcl/source/gdi/embeddedfontshelper \ + vcl/source/gdi/FileDefinitionWidgetDraw \ + vcl/source/gdi/WidgetDefinitionReader \ + vcl/source/gdi/WidgetDefinition \ + vcl/source/gdi/extoutdevdata \ + vcl/source/gdi/gdimtf \ + vcl/source/gdi/mtfxmldump \ + vcl/source/gdi/gdimetafiletools \ + vcl/source/gdi/gfxlink \ + vcl/source/gdi/gradient \ + vcl/source/gdi/graph \ + vcl/source/gdi/graphictools \ + vcl/source/gdi/hatch \ + vcl/source/gdi/impanmvw \ + vcl/source/gdi/impglyphitem \ + vcl/source/gdi/impgraph \ + vcl/source/gdi/impvect \ + vcl/source/gdi/jobset \ + vcl/source/gdi/lineinfo \ + vcl/source/gdi/mapmod \ + vcl/source/gdi/metaact \ + vcl/source/gdi/oldprintadaptor \ + vcl/source/gdi/pdfbuildin_fonts \ + vcl/source/gdi/pdfextoutdevdata \ + vcl/source/gdi/pdffontcache \ + vcl/source/gdi/pdfwriter \ + vcl/source/gdi/pdfwriter_impl2 \ + vcl/source/gdi/pdfwriter_impl \ + vcl/source/gdi/print2 \ + vcl/source/gdi/print3 \ + vcl/source/gdi/print \ + vcl/source/gdi/regband \ + vcl/source/gdi/region \ + vcl/source/gdi/regionband \ + vcl/source/gdi/salgdilayout \ + vcl/source/gdi/salgdiimpl \ + vcl/source/gdi/sallayout \ + vcl/source/gdi/salmisc \ + vcl/source/gdi/vectorgraphicdata \ + vcl/source/gdi/textlayout \ + vcl/source/gdi/virdev \ + vcl/source/gdi/wall \ + vcl/source/gdi/scrptrun \ + vcl/source/gdi/CommonSalLayout \ + vcl/source/gdi/TypeSerializer \ + vcl/source/pdf/ResourceDict \ + vcl/source/pdf/Matrix3 \ + vcl/source/pdf/XmpMetadata \ + vcl/source/pdf/PDFiumLibrary \ + vcl/source/graphic/GraphicID \ + vcl/source/graphic/GraphicLoader \ + vcl/source/graphic/GraphicObject \ + vcl/source/graphic/GraphicObject2 \ + vcl/source/graphic/GraphicReader \ + vcl/source/graphic/grfattr \ + vcl/source/graphic/Manager \ + vcl/source/graphic/UnoGraphic \ + vcl/source/graphic/UnoGraphicDescriptor \ + vcl/source/graphic/UnoGraphicObject \ + vcl/source/graphic/UnoGraphicProvider \ + vcl/source/graphic/UnoGraphicTransformer \ + vcl/source/bitmap/bitmap \ + vcl/source/bitmap/bitmapfilter \ + vcl/source/bitmap/BitmapAlphaClampFilter \ + vcl/source/bitmap/BitmapBasicMorphologyFilter \ + vcl/source/bitmap/BitmapMonochromeFilter \ + vcl/source/bitmap/BitmapSmoothenFilter \ + vcl/source/bitmap/BitmapLightenFilter \ + vcl/source/bitmap/BitmapDisabledImageFilter \ + vcl/source/bitmap/BitmapColorizeFilter \ + vcl/source/bitmap/bitmappaint \ + vcl/source/bitmap/BitmapGaussianSeparableBlurFilter \ + vcl/source/bitmap/BitmapSobelGreyFilter \ + vcl/source/bitmap/BitmapSolarizeFilter \ + vcl/source/bitmap/BitmapSepiaFilter \ + vcl/source/bitmap/BitmapMosaicFilter \ + vcl/source/bitmap/BitmapEmbossGreyFilter \ + vcl/source/bitmap/BitmapPopArtFilter \ + vcl/source/bitmap/BitmapDuoToneFilter \ + vcl/source/bitmap/BitmapConvolutionMatrixFilter \ + vcl/source/bitmap/BitmapMedianFilter \ + vcl/source/bitmap/BitmapInterpolateScaleFilter \ + vcl/source/bitmap/BitmapSeparableUnsharpenFilter \ + vcl/source/bitmap/BitmapFastScaleFilter \ + vcl/source/bitmap/BitmapScaleSuperFilter \ + vcl/source/bitmap/BitmapScaleConvolutionFilter \ + vcl/source/bitmap/BitmapSymmetryCheck \ + vcl/source/bitmap/BitmapColorQuantizationFilter \ + vcl/source/bitmap/BitmapSimpleColorQuantizationFilter \ + vcl/source/bitmap/BitmapTools \ + vcl/source/bitmap/checksum \ + vcl/source/bitmap/Octree \ + vcl/source/bitmap/salbmp \ + vcl/source/image/Image \ + vcl/source/image/ImageTree \ + vcl/source/image/ImageRepository \ + vcl/source/image/ImplImage \ + vcl/source/image/ImplImageTree \ + vcl/source/bitmap/BitmapFilterStackBlur \ + vcl/source/helper/canvasbitmap \ + vcl/source/helper/canvastools \ + vcl/source/helper/commandinfoprovider \ + vcl/source/helper/displayconnectiondispatch \ + vcl/source/helper/driverblocklist \ + vcl/source/helper/errcode \ + vcl/source/helper/evntpost \ + vcl/source/helper/lazydelete \ + vcl/source/helper/strhelper \ + vcl/source/helper/svtaccessiblefactory \ + vcl/source/helper/threadex \ + vcl/source/app/brand \ + vcl/source/app/customweld \ + vcl/source/app/dbggui \ + vcl/source/app/dndhelp \ + vcl/source/app/help \ + vcl/source/app/i18nhelp \ + vcl/source/app/idle \ + vcl/source/app/salusereventlist \ + vcl/source/app/salvtables \ + vcl/source/app/scheduler \ + vcl/source/app/session \ + vcl/source/app/settings \ + vcl/source/app/IconThemeInfo \ + vcl/source/app/IconThemeScanner \ + vcl/source/app/IconThemeSelector \ + vcl/source/app/ITiledRenderable \ + vcl/source/app/sound \ + vcl/source/app/stdtext \ + vcl/source/app/svapp \ + vcl/source/app/svdata \ + vcl/source/app/svmain \ + vcl/source/app/timer \ + vcl/source/app/unohelp2 \ + vcl/source/app/unohelp \ + vcl/source/app/vclevent \ + vcl/source/app/watchdog \ + vcl/source/app/weldutils \ + vcl/source/app/winscheduler \ + vcl/source/components/dtranscomp \ + vcl/source/components/factory \ + vcl/source/components/fontident \ + vcl/source/filter/FilterConfigCache \ + vcl/source/filter/FilterConfigItem \ + vcl/source/filter/graphicfilter \ + vcl/source/filter/graphicfilter2 \ + vcl/source/filter/GraphicNativeTransform \ + vcl/source/filter/GraphicNativeMetadata \ + vcl/source/filter/GraphicFormatDetector \ + vcl/source/filter/igif/decode \ + vcl/source/filter/igif/gifread \ + vcl/source/filter/ipdf/pdfread \ + vcl/source/filter/ipdf/pdfdocument \ + vcl/source/filter/ixbm/xbmread \ + vcl/source/filter/ixpm/xpmread \ + vcl/source/filter/jpeg/Exif \ + vcl/source/filter/jpeg/jpeg \ + vcl/source/filter/jpeg/jpegc \ + vcl/source/filter/jpeg/JpegReader \ + vcl/source/filter/jpeg/JpegWriter \ + vcl/source/filter/jpeg/JpegTransform \ + vcl/source/filter/wmf/emfwr \ + vcl/source/filter/wmf/wmf \ + vcl/source/filter/wmf/wmfexternal \ + vcl/source/filter/wmf/wmfwr \ + vcl/source/filter/png/PngImageReader \ + vcl/source/filter/png/pngread \ + vcl/source/filter/png/pngwrite \ + vcl/source/font/Feature \ + vcl/source/font/FeatureCollector \ + vcl/source/font/FeatureParser \ + vcl/source/font/OpenTypeFeatureDefinitionList \ + vcl/source/font/PhysicalFontCollection \ + vcl/source/font/PhysicalFontFace \ + vcl/source/font/PhysicalFontFamily \ + vcl/source/font/fontattributes \ + vcl/source/font/fontselect \ + vcl/source/font/fontinstance \ + vcl/source/font/fontcache \ + vcl/source/font/fontcharmap \ + vcl/source/font/fontmetric \ + vcl/source/font/font \ + vcl/source/fontsubset/cff \ + vcl/source/fontsubset/fontsubset \ + vcl/source/fontsubset/list \ + vcl/source/fontsubset/sft \ + vcl/source/fontsubset/ttcr \ + vcl/source/fontsubset/xlat \ + vcl/source/uitest/logger \ + vcl/source/uitest/uiobject \ + vcl/source/uitest/uitest \ + vcl/source/uitest/uno/uiobject_uno \ + vcl/source/uitest/uno/uitest_uno \ + vcl/backendtest/outputdevice/bitmap \ + vcl/backendtest/outputdevice/clip \ + vcl/backendtest/outputdevice/common \ + vcl/backendtest/outputdevice/gradient \ + vcl/backendtest/outputdevice/line \ + vcl/backendtest/outputdevice/outputdevice \ + vcl/backendtest/outputdevice/pixel \ + vcl/backendtest/outputdevice/polygon \ + vcl/backendtest/outputdevice/polypolygon \ + vcl/backendtest/outputdevice/polypolygon_b2d \ + vcl/backendtest/outputdevice/polyline \ + vcl/backendtest/outputdevice/polyline_b2d \ + vcl/backendtest/outputdevice/rectangle \ + vcl/jsdialog/jsdialogbuilder \ +)) + +$(eval $(call gb_Library_add_cobjects,vcl,\ + vcl/source/filter/jpeg/transupp \ +)) + +vcl_quartz_code= \ + vcl/quartz/salbmp \ + vcl/quartz/utils \ + vcl/quartz/salgdicommon \ + vcl/quartz/salvd \ + +vcl_coretext_code= \ + vcl/quartz/ctfonts \ + vcl/quartz/salgdi \ + +vcl_headless_code= \ + vcl/headless/svpframe \ + $(if $(filter-out iOS,$(OS)), \ + vcl/headless/svpbmp \ + vcl/headless/svpgdi \ + vcl/headless/svpdata \ + vcl/headless/CustomWidgetDraw) \ + vcl/headless/svpdummies \ + vcl/headless/svpinst \ + vcl/headless/svpvd \ + vcl/unx/generic/app/gendisp \ + vcl/unx/generic/app/geninst \ + vcl/unx/generic/app/gensys \ + +vcl_headless_freetype_code=\ + vcl/headless/svpprn \ + vcl/headless/svptext \ + vcl/unx/generic/app/gendata \ + vcl/unx/generic/gdi/cairotextrender \ + vcl/unx/generic/gdi/freetypetextrender \ + vcl/unx/generic/glyphs/freetype_glyphcache \ + vcl/unx/generic/glyphs/glyphcache \ + vcl/unx/generic/fontmanager/fontsubst \ + vcl/unx/generic/fontmanager/fontconfig \ + vcl/unx/generic/fontmanager/fontmanager \ + vcl/unx/generic/fontmanager/helper \ + vcl/headless/svpcairotextrender \ + vcl/unx/generic/print/bitmap_gfx \ + vcl/unx/generic/print/common_gfx \ + vcl/unx/generic/print/glyphset \ + vcl/unx/generic/print/printerjob \ + vcl/unx/generic/print/psputil \ + vcl/unx/generic/print/genpspgraphics \ + vcl/unx/generic/print/genprnpsp \ + vcl/unx/generic/print/prtsetup \ + vcl/unx/generic/print/text_gfx \ + +ifeq ($(USING_X11),TRUE) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/source/app/salplug \ + vcl/unx/generic/printer/jobdata \ + vcl/unx/generic/printer/ppdparser \ + vcl/unx/generic/gdi/nativewindowhandleprovider \ + vcl/unx/generic/window/screensaverinhibitor \ + vcl/unx/generic/printer/cpdmgr \ + $(if $(filter TRUE,$(ENABLE_CUPS)),\ + vcl/unx/generic/printer/cupsmgr \ + vcl/unx/generic/printer/printerinfomanager \ + , \ + vcl/null/printerinfomanager \ + ) \ + $(vcl_headless_code) \ + $(vcl_headless_freetype_code) \ +)) + +$(eval $(call gb_Library_use_externals,vcl,\ + cairo \ + cups \ + dbus \ + fontconfig \ + freetype \ + valgrind \ +)) +endif + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Library_add_libs,vcl,\ + -lm $(DLOPEN_LIBS) \ +)) +endif + +ifeq ($(DISABLE_GUI),TRUE) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/unx/generic/printer/jobdata \ + vcl/unx/generic/printer/ppdparser \ + vcl/null/printerinfomanager \ + vcl/headless/headlessinst \ + vcl/skia/SkiaHelper \ + $(vcl_headless_code) \ + $(vcl_headless_freetype_code) \ +)) + +$(eval $(call gb_Library_use_externals,vcl,\ + cairo \ + freetype \ + fontconfig \ +)) + +else # ! DISABLE_GUI + +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/opengl/DeviceInfo \ + vcl/opengl/gdiimpl \ + vcl/opengl/salbmp \ + vcl/opengl/scale \ + vcl/opengl/framebuffer \ + vcl/opengl/program \ + vcl/opengl/texture \ + vcl/opengl/FixedTextureAtlas \ + vcl/opengl/PackedTextureAtlas \ + vcl/opengl/RenderList \ + vcl/opengl/LineRenderUtils \ + vcl/source/opengl/OpenGLContext \ + vcl/source/opengl/OpenGLHelper \ + vcl/skia/SkiaHelper \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + vcl/skia/salbmp \ + vcl/skia/zone \ + vcl/skia/gdiimpl \ + ) \ + )) + +# runtime dependency +$(eval $(call gb_Library_use_package,vcl,vcl_opengl_shader)) +ifeq ($(OS),WNT) +$(eval $(call gb_Library_use_package,vcl,vcl_opengl_blacklist)) +endif + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +$(eval $(call gb_Library_add_libs,vcl,\ + -lX11 \ + -lXext \ +)) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/opengl/x11/X11DeviceInfo \ +)) +endif +endif # ! DISABLE_GUI + + +ifeq ($(OS),HAIKU) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/unx/generic/printer/jobdata \ + vcl/unx/generic/printer/ppdparser \ + vcl/null/printerinfomanager \ + $(vcl_headless_code) \ + $(vcl_headless_freetype_code) \ +)) + +$(eval $(call gb_Library_add_libs,vcl,\ + -lbe \ +)) + +$(eval $(call gb_Library_add_exception_objects,vcl, \ + $(if $(or $(ENABLE_QT5),$(ENABLE_KF5)),vcl/source/app/salplug) \ +)) + +$(eval $(call gb_Library_use_externals,vcl,\ + cairo \ + fontconfig \ + freetype \ + expat \ +)) +endif + + +ifeq ($(OS),ANDROID) +$(eval $(call gb_Library_add_libs,vcl,\ + -llog \ + -landroid \ + -llo-bootstrap \ +)) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/unx/generic/printer/jobdata \ + vcl/unx/generic/printer/ppdparser \ + vcl/null/printerinfomanager \ + vcl/android/androidinst \ + $(vcl_headless_code) \ + $(vcl_headless_freetype_code) \ +)) + +$(eval $(call gb_Library_use_externals,vcl,\ + cairo \ + fontconfig \ + freetype \ + expat \ +)) +endif + + +ifeq ($(OS),iOS) +$(eval $(call gb_Library_add_cxxflags,vcl,\ + $(gb_OBJCXXFLAGS) \ +)) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/ios/iosinst \ + vcl/ios/dummies \ + vcl/ios/clipboard \ + vcl/ios/iOSTransferable \ + vcl/ios/DataFlavorMapping \ + vcl/ios/HtmlFmtFlt \ + $(vcl_coretext_code) \ + $(vcl_quartz_code) \ + $(vcl_headless_code) \ +)) +$(eval $(call gb_Library_use_system_darwin_frameworks,vcl,\ + UIKit \ + CoreFoundation \ +)) +endif + + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Library_use_system_darwin_frameworks,vcl,\ + Cocoa \ + CoreFoundation \ +)) + +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/source/app/salplug \ +)) +endif + + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/opengl/win/WinDeviceInfo \ + vcl/source/app/salplug \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,vcl,\ + ole32 \ + setupapi \ + version \ +)) + +$(eval $(call gb_Library_add_nativeres,vcl,vcl/salsrc)) + +# HACK: dependency on icon themes so running unit tests don't +# prevent delivering these by having open file handles on WNT +$(eval $(call gb_Library_use_package,vcl,postprocess_images)) +endif + +ifeq ($(OS), $(filter LINUX %BSD SOLARIS, $(OS))) +ifeq ($(USING_X11),TRUE) +$(eval $(call gb_Library_use_static_libraries,vcl,\ + glxtest \ +)) +endif +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_gen.mk b/vcl/Library_vclplug_gen.mk new file mode 100644 index 000000000..36652b701 --- /dev/null +++ b/vcl/Library_vclplug_gen.mk @@ -0,0 +1,161 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_gen)) + +$(eval $(call gb_Library_set_include,vclplug_gen,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_gen,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_gen)) + +$(eval $(call gb_Library_use_common_precompiled_header,vclplug_gen)) + +$(eval $(call gb_Library_use_libraries,vclplug_gen,\ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_gen,\ + boost_headers \ + cairo \ + graphite \ + epoxy \ + glm_headers \ + harfbuzz \ + icu_headers \ + icuuc \ + valgrind \ + Xrender \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + skia \ + fontconfig \ + ) \ +)) + +$(eval $(call gb_Library_add_libs,vclplug_gen,\ + -lX11 \ + -lXext \ + -lSM \ + -lICE \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_gen,\ + vcl/unx/generic/app/i18n_cb \ + vcl/unx/generic/app/i18n_ic \ + vcl/unx/generic/app/i18n_im \ + vcl/unx/generic/app/i18n_keysym \ + vcl/unx/generic/app/i18n_xkb \ + vcl/unx/generic/app/keysymnames \ + vcl/unx/generic/app/randrwrapper \ + vcl/unx/generic/app/saldata \ + vcl/unx/generic/app/saldisp \ + vcl/unx/generic/app/salinst \ + vcl/unx/generic/app/saltimer \ + vcl/unx/generic/app/sm \ + vcl/unx/generic/app/wmadaptor \ + vcl/unx/generic/dtrans/bmp \ + vcl/unx/generic/dtrans/config \ + vcl/unx/generic/dtrans/X11_clipboard \ + vcl/unx/generic/dtrans/X11_dndcontext \ + vcl/unx/generic/dtrans/X11_droptarget \ + vcl/unx/generic/dtrans/X11_selection \ + vcl/unx/generic/dtrans/X11_service \ + vcl/unx/generic/dtrans/X11_transferable \ + vcl/unx/generic/gdi/cairo_xlib_cairo \ + vcl/unx/generic/gdi/x11cairotextrender \ + vcl/unx/generic/gdi/gdiimpl \ + vcl/unx/generic/gdi/salbmp \ + vcl/unx/generic/gdi/salgdi2 \ + vcl/unx/generic/gdi/font \ + vcl/unx/generic/gdi/salgdi \ + vcl/unx/generic/gdi/salvd \ + vcl/unx/generic/gdi/xrender_peer \ + vcl/unx/generic/window/salframe \ + vcl/unx/generic/window/salobj \ + vcl/unx/x11/x11sys \ + vcl/unx/x11/xlimits \ + vcl/opengl/x11/cairotextrender \ + vcl/opengl/x11/gdiimpl \ + vcl/opengl/x11/salvd \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + vcl/skia/x11/gdiimpl \ + vcl/skia/x11/salvd \ + vcl/skia/x11/textrender \ + ) \ +)) + +# ultimately we want to split the x11 dependencies out +# into their own library I think. + +$(eval $(call gb_Library_add_defs,vclplug_gen,\ + -DVCLPLUG_GEN_IMPLEMENTATION \ +)) + +## handle RandR +ifneq ($(ENABLE_RANDR),) +$(eval $(call gb_Library_use_externals,vclplug_gen,\ + Xrandr \ +)) +$(eval $(call gb_Library_add_defs,vclplug_gen,\ + -DUSE_RANDR \ +)) +endif + +## handle Xinerama +ifneq ($(USE_XINERAMA),) +$(eval $(call gb_Library_add_defs,vclplug_gen,\ + -DUSE_XINERAMA_XORG \ +)) +ifeq ($(XINERAMA_LINK),dynamic) +$(eval $(call gb_Library_add_libs,vclplug_gen,\ + -lXinerama \ +)) +else +$(eval $(call gb_Library_add_libs,vclplug_gen,\ + -Wl$(COMMA)-Bstatic -lXinerama -Wl$(COMMA)-Bdynamic \ +)) +endif +endif # USE_XINERAMA + +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,vclplug_gen,\ + -lm \ + -ldl \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_gtk3.mk b/vcl/Library_vclplug_gtk3.mk new file mode 100644 index 000000000..9e67d5efc --- /dev/null +++ b/vcl/Library_vclplug_gtk3.mk @@ -0,0 +1,124 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_gtk3)) + +# Silence deprecation warnings wholesale as long as vcl/unx/gtk3/*.cxx just +# forward to vcl/unx/gtk/*.cxx: +$(eval $(call gb_Library_add_cxxflags,vclplug_gtk3, \ + -Wno-deprecated-declarations \ +)) + +$(eval $(call gb_Library_set_include,vclplug_gtk3,\ + $$(INCLUDE) \ + $$(GTK3_CFLAGS) \ + $$(GSTREAMER_1_0_CFLAGS) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/unx \ + -I$(SRCDIR)/vcl/unx/gtk3 \ +)) + +$(eval $(call gb_Library_add_defs,vclplug_gtk3,\ + -DVCLPLUG_GTK_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_gtk3,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_gtk3)) + +$(eval $(call gb_Library_add_libs,vclplug_gtk3,\ + $(GTK3_LIBS) \ + -lX11 \ + -lXext \ + -lSM \ + -lICE \ +)) + +$(eval $(call gb_Library_use_libraries,vclplug_gtk3,\ + vcl \ + svl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_gtk3,\ + boost_headers \ + epoxy \ + dbus \ + graphite \ + harfbuzz \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_gtk3,\ + vcl/unx/gtk3/a11y/gtk3atkaction \ + vcl/unx/gtk3/a11y/gtk3atkbridge \ + vcl/unx/gtk3/a11y/gtk3atkcomponent \ + vcl/unx/gtk3/a11y/gtk3atkeditabletext \ + vcl/unx/gtk3/a11y/gtk3atkfactory \ + vcl/unx/gtk3/a11y/gtk3atkhypertext \ + vcl/unx/gtk3/a11y/gtk3atkimage \ + vcl/unx/gtk3/a11y/gtk3atklistener \ + vcl/unx/gtk3/a11y/gtk3atkregistry \ + vcl/unx/gtk3/a11y/gtk3atkselection \ + vcl/unx/gtk3/a11y/gtk3atktable \ + vcl/unx/gtk3/a11y/gtk3atktextattributes \ + vcl/unx/gtk3/a11y/gtk3atktext \ + vcl/unx/gtk3/a11y/gtk3atkutil \ + vcl/unx/gtk3/a11y/gtk3atkvalue \ + vcl/unx/gtk3/a11y/gtk3atkwrapper \ + vcl/unx/gtk3/fpicker/resourceprovider \ + vcl/unx/gtk3/fpicker/SalGtkFilePicker \ + vcl/unx/gtk3/fpicker/SalGtkFolderPicker \ + vcl/unx/gtk3/fpicker/SalGtkPicker \ + vcl/unx/gtk3/gtk3gtkdata \ + vcl/unx/gtk3/gtk3gtkinst \ + vcl/unx/gtk3/gtk3gtksys \ + vcl/unx/gtk3/cairo_gtk3_cairo \ + vcl/unx/gtk3/gtk3gtkprintwrapper \ + vcl/unx/gtk3/gtk3salnativewidgets-gtk \ + vcl/unx/gtk3/gtk3salprn-gtk \ + vcl/unx/gtk3/gtk3gtkframe \ + vcl/unx/gtk3/gtk3gtkobject \ + vcl/unx/gtk3/gtk3gtksalmenu \ + vcl/unx/gtk3/gtk3glomenu \ + vcl/unx/gtk3/gtk3gloactiongroup \ + vcl/unx/gtk3/gtk3hudawareness \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,vclplug_gtk3,\ + -lm \ + -ldl \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_gtk3_kde5.mk b/vcl/Library_vclplug_gtk3_kde5.mk new file mode 100644 index 000000000..51dafda09 --- /dev/null +++ b/vcl/Library_vclplug_gtk3_kde5.mk @@ -0,0 +1,130 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_gtk3_kde5)) + +# Silence deprecation warnings wholesale as long as vcl/unx/gtk3/*.cxx just +# forward to vcl/unx/gtk/*.cxx: +$(eval $(call gb_Library_add_cxxflags,vclplug_gtk3_kde5, \ + -Wno-deprecated-declarations \ +)) + +$(eval $(call gb_Library_set_include,vclplug_gtk3_kde5,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/unx \ + -I$(SRCDIR)/vcl/unx/gtk3 \ +)) + +$(eval $(call gb_Library_add_cxxflags,vclplug_gtk3_kde5,\ + $$(INCLUDE) \ + $$(GTK3_CFLAGS) \ + $(KF5_CFLAGS) \ + $$(GSTREAMER_1_0_CFLAGS) \ +)) + +$(eval $(call gb_Library_add_defs,vclplug_gtk3_kde5,\ + -DVCLPLUG_GTK_IMPLEMENTATION -DVCLPLUG_GTK3_KDE5_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_gtk3_kde5,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_gtk3_kde5)) + +$(eval $(call gb_Library_add_libs,vclplug_gtk3_kde5,\ + $(GTK3_LIBS) \ + -lX11 \ + -lXext \ + -lSM \ + -lICE \ +)) + +$(eval $(call gb_Library_use_libraries,vclplug_gtk3_kde5,\ + svl \ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_gtk3_kde5,\ + boost_headers \ + boost_filesystem \ + epoxy \ + dbus \ + graphite \ + harfbuzz \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_gtk3_kde5,\ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkaction \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkbridge \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkcomponent \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkeditabletext \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkfactory \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkhypertext \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkimage \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atklistener \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkregistry \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkselection \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktable \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktextattributes \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atktext \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkutil \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkvalue \ + vcl/unx/gtk3_kde5/a11y/gtk3_kde5_atkwrapper \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtkdata \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtkinst \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtksys \ + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker \ + vcl/unx/gtk3_kde5/gtk3_kde5_filepicker_ipc \ + vcl/unx/gtk3_kde5/gtk3_kde5_folderpicker \ + vcl/unx/gtk3_kde5/gtk3_kde5_cairo \ + vcl/unx/gtk3_kde5/gtk3_kde5_printwrapper \ + vcl/unx/gtk3_kde5/gtk3_kde5_salnativewidgets-gtk \ + vcl/unx/gtk3_kde5/gtk3_kde5_salprn-gtk \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtkframe \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtkobject \ + vcl/unx/gtk3_kde5/gtk3_kde5_gtksalmenu \ + vcl/unx/gtk3_kde5/gtk3_kde5_glomenu \ + vcl/unx/gtk3_kde5/gtk3_kde5_gloactiongroup \ + vcl/unx/gtk3_kde5/gtk3_kde5_hudawareness \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,vclplug_gtk3_kde5,\ + -lm \ + -ldl \ + $(KF5_LIBS) \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_kf5.mk b/vcl/Library_vclplug_kf5.mk new file mode 100644 index 000000000..d10cecd16 --- /dev/null +++ b/vcl/Library_vclplug_kf5.mk @@ -0,0 +1,92 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_kf5)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_kf5,vcl/unx/kf5)) + +$(eval $(call gb_Library_set_include,vclplug_kf5,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/inc/qt5 \ +)) + +$(eval $(call gb_Library_add_defs,vclplug_kf5,\ + -DVCLPLUG_KF5_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_kf5)) + +$(eval $(call gb_Library_use_libraries,vclplug_kf5,\ + vclplug_qt5 \ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_kf5,\ + boost_headers \ + cairo \ + graphite \ + harfbuzz \ + icuuc \ + kf5 \ + epoxy \ +)) + +$(eval $(call gb_Library_add_cxxflags,vclplug_kf5,\ + $(KF5_CFLAGS) \ +)) +$(eval $(call gb_Library_add_libs,vclplug_kf5,\ + $(KF5_LIBS) \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_kf5,\ + vcl/unx/kf5/KF5FilePicker \ + vcl/unx/kf5/KF5SalFrame \ + vcl/unx/kf5/KF5SalInstance \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,vclplug_kf5,\ + -lm \ + -ldl \ +)) +endif + +# Workaround for clang+icecream (clang's -frewrite-includes +# doesn't handle Qt5's QT_HAS_INCLUDE that Qt5 uses for ). +ifeq ($(COM_IS_CLANG),TRUE) +$(eval $(call gb_Library_add_cxxflags,vclplug_kf5, \ + -include chrono \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_osx.mk b/vcl/Library_vclplug_osx.mk new file mode 100644 index 000000000..f0d22298a --- /dev/null +++ b/vcl/Library_vclplug_osx.mk @@ -0,0 +1,153 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_osx)) + +$(eval $(call gb_Library_set_include,vclplug_osx,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_osx)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_osx,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_add_libs,vclplug_osx,\ + -framework IOKit \ + -F/System/Library/PrivateFrameworks \ + -framework CoreUI \ + -lobjc \ +)) + +$(eval $(call gb_Library_add_cxxflags,vclplug_osx,\ + $(gb_OBJCXXFLAGS) \ +)) + +$(eval $(call gb_Library_use_libraries,vclplug_osx,\ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + sal \ + salhelper \ + tl \ + vcl \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_osx,\ + boost_headers \ + harfbuzz \ +)) + +ifeq ($(DISABLE_GUI),) +$(eval $(call gb_Library_use_externals,vclplug_osx,\ + epoxy \ +)) +endif + +$(eval $(call gb_Library_add_defs,vclplug_osx,\ + -DMACOSX_BUNDLE_IDENTIFIER=\"$(MACOSX_BUNDLE_IDENTIFIER)\" \ +)) + +$(eval $(call gb_Library_add_objcxxobjects,vclplug_osx,\ + vcl/osx/a11yactionwrapper \ + vcl/osx/a11ycomponentwrapper \ + vcl/osx/a11yfactory \ + vcl/osx/a11yrolehelper \ + vcl/osx/a11yselectionwrapper \ + vcl/osx/a11ytablewrapper \ + vcl/osx/a11ytextattributeswrapper \ + vcl/osx/a11ytextwrapper \ + vcl/osx/a11yutil \ + vcl/osx/a11yvaluewrapper \ + vcl/osx/a11ywrapper \ + vcl/osx/a11ywrapperbutton \ + vcl/osx/a11ywrappercheckbox \ + vcl/osx/a11ywrappercombobox \ + vcl/osx/a11ywrappergroup \ + vcl/osx/a11ywrapperlist \ + vcl/osx/a11ywrapperradiobutton \ + vcl/osx/a11ywrapperradiogroup \ + vcl/osx/a11ywrapperrow \ + vcl/osx/a11ywrapperscrollarea \ + vcl/osx/a11ywrapperscrollbar \ + vcl/osx/a11ywrappersplitter \ + vcl/osx/a11ywrapperstatictext \ + vcl/osx/a11ywrappertabgroup \ + vcl/osx/a11ywrappertextarea \ + vcl/osx/a11ywrappertoolbar \ + vcl/osx/printaccessoryview \ + vcl/osx/printview \ + vcl/osx/salframeview \ + vcl/osx/salnsmenu \ + vcl/osx/salnstimer \ + vcl/osx/vclnsapp \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_osx,\ + vcl/osx/DataFlavorMapping \ + vcl/osx/DragActionConversion \ + vcl/osx/DragSource \ + vcl/osx/DragSourceContext \ + vcl/osx/DropTarget \ + vcl/osx/HtmlFmtFlt \ + vcl/osx/OSXTransferable \ + vcl/osx/PictToBmpFlt \ + vcl/osx/a11yfocuslistener \ + vcl/osx/a11yfocustracker \ + vcl/osx/a11ylistener \ + vcl/osx/clipboard \ + vcl/osx/documentfocuslistener \ + vcl/osx/saldata \ + vcl/osx/salframe \ + vcl/osx/salinst \ + vcl/osx/salmenu \ + vcl/osx/salnativewidgets \ + vcl/osx/salobj \ + vcl/osx/salprn \ + vcl/osx/salsys \ + vcl/osx/saltimer \ + vcl/osx/service_entry \ + vcl/quartz/ctfonts \ + vcl/quartz/salbmp \ + vcl/quartz/salgdi \ + vcl/quartz/salgdicommon \ + vcl/quartz/salgdiutils \ + vcl/quartz/salvd \ + vcl/quartz/utils \ +)) + +$(eval $(call gb_Library_use_system_darwin_frameworks,vclplug_osx,\ + ApplicationServices \ + Cocoa \ + Carbon \ + CoreFoundation \ +)) + +ifneq ($(ENABLE_MACOSX_SANDBOX),TRUE) +$(eval $(call gb_Library_use_libraries,vclplug_osx,\ + AppleRemote \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk new file mode 100644 index 000000000..25cbfe9f6 --- /dev/null +++ b/vcl/Library_vclplug_qt5.mk @@ -0,0 +1,131 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_qt5)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_qt5,vcl/qt5)) + +$(eval $(call gb_Library_set_include,vclplug_qt5,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/inc/qt5 \ + $(GSTREAMER_1_0_CFLAGS) \ +)) + +$(eval $(call gb_Library_add_defs,vclplug_qt5,\ + -DVCLPLUG_QT5_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_qt5)) + +$(eval $(call gb_Library_use_libraries,vclplug_qt5,\ + vcl \ + tl \ + utl \ + sot \ + ucbhelper \ + basegfx \ + comphelper \ + cppuhelper \ + i18nlangtag \ + i18nutil \ + $(if $(ENABLE_JAVA), \ + jvmaccess) \ + cppu \ + sal \ + salhelper \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_qt5,\ + boost_headers \ + cairo \ + epoxy \ + graphite \ + harfbuzz \ + icu_headers \ + icuuc \ + qt5 \ +)) + +$(eval $(call gb_Library_add_cxxflags,vclplug_qt5,\ + $(QT5_CFLAGS) \ +)) +$(eval $(call gb_Library_add_libs,vclplug_qt5,\ + $(QT5_LIBS) \ +)) + +ifneq ($(QT5_HAVE_GOBJECT),) +$(eval $(call gb_Library_add_cxxflags,vclplug_qt5,\ + $(QT5_GOBJECT_CFLAGS) \ +)) +$(eval $(call gb_Library_add_libs,vclplug_qt5,\ + $(QT5_GOBJECT_LIBS) \ +)) +endif + +$(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\ + vcl/qt5/Qt5AccessibleEventListener \ + vcl/qt5/Qt5AccessibleWidget \ + vcl/qt5/Qt5Bitmap \ + vcl/qt5/Qt5Clipboard \ + vcl/qt5/Qt5Data \ + vcl/qt5/Qt5DragAndDrop \ + vcl/qt5/Qt5FilePicker \ + vcl/qt5/Qt5Font \ + vcl/qt5/Qt5FontFace \ + vcl/qt5/Qt5Frame \ + vcl/qt5/Qt5Graphics \ + vcl/qt5/Qt5Graphics_Controls \ + vcl/qt5/Qt5Graphics_GDI \ + vcl/qt5/Qt5Graphics_Text \ + vcl/qt5/Qt5Instance \ + vcl/qt5/Qt5Instance_Print \ + vcl/qt5/Qt5MainWindow \ + vcl/qt5/Qt5Menu \ + vcl/qt5/Qt5Object \ + vcl/qt5/Qt5OpenGLContext \ + vcl/qt5/Qt5Painter \ + vcl/qt5/Qt5Printer \ + vcl/qt5/Qt5SvpGraphics \ + vcl/qt5/Qt5SvpSurface \ + vcl/qt5/Qt5System \ + vcl/qt5/Qt5Timer \ + vcl/qt5/Qt5Tools \ + vcl/qt5/Qt5Transferable \ + vcl/qt5/Qt5VirtualDevice \ + vcl/qt5/Qt5Widget \ + vcl/qt5/Qt5XAccessible \ +)) + +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,vclplug_qt5,\ + -lm \ + -ldl \ +)) +endif + +# Workaround for clang+icecream (clang's -frewrite-includes +# doesn't handle Qt5's QT_HAS_INCLUDE that Qt5 uses for ). +ifeq ($(COM_IS_CLANG),TRUE) +$(eval $(call gb_Library_add_cxxflags,vclplug_qt5, \ + -include chrono \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_win.mk b/vcl/Library_vclplug_win.mk new file mode 100644 index 000000000..2e169ded8 --- /dev/null +++ b/vcl/Library_vclplug_win.mk @@ -0,0 +1,109 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,vclplug_win)) + +$(eval $(call gb_Library_set_include,vclplug_win,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/vcl/inc/win \ +)) + +$(eval $(call gb_Library_add_defs,vclplug_win,\ + -DVCLPLUG_WIN_IMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_custom_headers,vclplug_win,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,vclplug_win)) + +$(eval $(call gb_Library_use_common_precompiled_header,vclplugin_win)) + +$(eval $(call gb_Library_use_libraries,vclplug_win,\ + $(call gb_Helper_optional,BREAKPAD, \ + crashreport) \ + basegfx \ + comphelper \ + cppu \ + i18nlangtag \ + i18nutil \ + sal \ + salhelper \ + tl \ + utl \ + vcl \ +)) + +$(eval $(call gb_Library_use_externals,vclplug_win,\ + boost_headers \ + epoxy \ + glm_headers \ + harfbuzz \ + $(if $(filter SKIA,$(BUILD_TYPE)),skia) \ +)) + +$(eval $(call gb_Library_add_exception_objects,vclplug_win,\ + vcl/opengl/win/gdiimpl \ + vcl/opengl/win/winlayout \ + vcl/win/app/saldata \ + vcl/win/app/salinfo \ + vcl/win/app/salinst \ + vcl/win/app/salshl \ + vcl/win/app/saltimer \ + vcl/win/gdi/gdiimpl \ + vcl/win/gdi/salbmp \ + vcl/win/gdi/salgdi \ + vcl/win/gdi/salgdi2 \ + vcl/win/gdi/salfont \ + vcl/win/gdi/salgdi_gdiplus \ + vcl/win/gdi/salnativewidgets-luna \ + vcl/win/gdi/salprn \ + vcl/win/gdi/salvd \ + vcl/win/gdi/winlayout \ + vcl/win/gdi/DWriteTextRenderer \ + vcl/win/window/salframe \ + vcl/win/window/keynames \ + vcl/win/window/salmenu \ + vcl/win/window/salobj \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + vcl/skia/win/gdiimpl ) \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,vclplug_win,\ + d2d1 \ + dwrite \ + gdi32 \ + gdiplus \ + imm32 \ + ole32 \ + shell32 \ + shlwapi \ + version \ + winspool \ +)) + +$(eval $(call gb_Library_add_nativeres,vclplug_win,vcl/salsrc)) + +# HACK: dependency on icon themes so running unit tests don't +# prevent delivering these by having open file handles on WNT +$(eval $(call gb_Library_use_package,vclplug_win,postprocess_images)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Makefile b/vcl/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/vcl/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk new file mode 100644 index 000000000..938cd3201 --- /dev/null +++ b/vcl/Module_vcl.mk @@ -0,0 +1,255 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Module_Module,vcl)) + +$(eval $(call gb_Module_add_targets,vcl,\ + Library_vcl \ + Package_opengl_shader \ + Package_theme_definitions \ + Package_tipoftheday \ + UIConfig_vcl \ + $(if $(filter WNT,$(OS)), \ + Package_opengl_blacklist ) \ + $(if $(filter SKIA,$(BUILD_TYPE)), \ + Package_skia_blacklist ) \ + $(if $(filter DESKTOP,$(BUILD_TYPE)), \ + StaticLibrary_vclmain \ + $(if $(ENABLE_MACOSX_SANDBOX),, \ + $(if $(DISABLE_GUI),, \ + Executable_ui-previewer)) \ + $(if $(filter LINUX MACOSX SOLARIS WNT %BSD,$(OS)), \ + $(if $(DISABLE_GUI),, \ + Executable_vcldemo \ + Executable_icontest \ + Executable_visualbackendtest \ + Executable_mtfdemo ))) \ +)) + +ifeq ($(CROSS_COMPILING)$(DISABLE_DYNLOADING),) + +$(eval $(call gb_Module_add_targets,vcl,\ + $(if $(filter-out ANDROID iOS WNT,$(OS)), \ + Executable_svdemo \ + Executable_fftester \ + Executable_svptest \ + Executable_svpclient) \ +)) + +endif + +$(eval $(call gb_Module_add_l10n_targets,vcl,\ + AllLangMoTarget_vcl \ +)) + +ifeq ($(USING_X11),TRUE) +$(eval $(call gb_Module_add_targets,vcl,\ + Library_vclplug_gen \ + Library_desktop_detector \ + StaticLibrary_glxtest \ + Package_fontunxppds \ + Package_fontunxpsprint \ +)) + +ifneq ($(ENABLE_GTK3),) +$(eval $(call gb_Module_add_targets,vcl,\ + Library_vclplug_gtk3 \ +)) +endif +ifneq ($(ENABLE_KF5),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_kf5_moc \ + Library_vclplug_kf5 \ +)) +endif +ifneq ($(ENABLE_QT5),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_qt5_moc \ + Library_vclplug_qt5 \ +)) +endif +ifneq ($(ENABLE_GTK3_KDE5),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_gtk3_kde5_moc \ + Library_vclplug_gtk3_kde5 \ + Executable_lo_kde5filepicker \ +)) +endif +endif + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Module_add_targets,vcl,\ + Package_osxres \ + Library_vclplug_osx \ +)) +endif + +ifeq ($(OS),WNT) +$(eval $(call gb_Module_add_targets,vcl,\ + WinResTarget_vcl \ + Library_vclplug_win \ +)) +endif + +ifeq ($(OS),HAIKU) +ifneq ($(ENABLE_QT5),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_qt5_moc \ + Library_vclplug_qt5 \ +)) +endif +ifneq ($(ENABLE_KF5),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_kf5_moc \ + Library_vclplug_kf5 \ +)) +endif +endif + +ifneq ($(ENABLE_FUZZERS),) +$(eval $(call gb_Module_add_targets,vcl,\ + CustomTarget_nativecore \ + CustomTarget_nativecalc \ + CustomTarget_nativedraw \ + CustomTarget_nativewriter \ + CustomTarget_nativemath \ + StaticLibrary_fuzzerstubs \ + StaticLibrary_fuzzer_core \ + StaticLibrary_fuzzer_calc \ + StaticLibrary_fuzzer_draw \ + StaticLibrary_fuzzer_writer \ + StaticLibrary_fuzzer_math \ + Executable_wmffuzzer \ + Executable_jpgfuzzer \ + Executable_giffuzzer \ + Executable_xbmfuzzer \ + Executable_xpmfuzzer \ + Executable_pngfuzzer \ + Executable_bmpfuzzer \ + Executable_svmfuzzer \ + Executable_pcdfuzzer \ + Executable_dxffuzzer \ + Executable_metfuzzer \ + Executable_ppmfuzzer \ + Executable_psdfuzzer \ + Executable_epsfuzzer \ + Executable_pctfuzzer \ + Executable_pcxfuzzer \ + Executable_rasfuzzer \ + Executable_tgafuzzer \ + Executable_tiffuzzer \ + Executable_hwpfuzzer \ + Executable_602fuzzer \ + Executable_lwpfuzzer \ + Executable_olefuzzer \ + Executable_pptfuzzer \ + Executable_rtffuzzer \ + Executable_cgmfuzzer \ + Executable_ww2fuzzer \ + Executable_ww6fuzzer \ + Executable_ww8fuzzer \ + Executable_qpwfuzzer \ + Executable_slkfuzzer \ + Executable_fodtfuzzer \ + Executable_fodsfuzzer \ + Executable_fodpfuzzer \ + Executable_xlsfuzzer \ + Executable_scrtffuzzer \ + Executable_wksfuzzer \ + Executable_diffuzzer \ + Executable_docxfuzzer \ + Executable_xlsxfuzzer \ + Executable_pptxfuzzer \ + Executable_mmlfuzzer \ + Executable_mtpfuzzer \ + Executable_htmlfuzzer \ + Executable_sftfuzzer \ +)) +endif + +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_lifecycle \ + CppunitTest_vcl_bitmap_test \ + CppunitTest_vcl_bitmapprocessor_test \ + CppunitTest_vcl_graphic_test \ + CppunitTest_vcl_fontcharmap \ + CppunitTest_vcl_font \ + CppunitTest_vcl_fontfeature \ + CppunitTest_vcl_fontmetric \ + CppunitTest_vcl_complextext \ + CppunitTest_vcl_filters_test \ + CppunitTest_vcl_mnemonic \ + CppunitTest_vcl_outdev \ + CppunitTest_vcl_app_test \ + CppunitTest_vcl_jpeg_read_write_test \ + CppunitTest_vcl_svm_test \ + CppunitTest_vcl_errorhandler \ + CppunitTest_vcl_bitmap_render_test \ + CppunitTest_vcl_apitests \ + CppunitTest_vcl_png_test \ + CppunitTest_vcl_widget_definition_reader_test \ + CppunitTest_vcl_backend_test \ + CppunitTest_vcl_blocklistparser_test \ + CppunitTest_vcl_type_serializer_test \ +)) + +ifeq ($(USING_X11),TRUE) +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_timer \ +)) +endif + +ifeq ($(DISABLE_GUI),TRUE) +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_timer \ +)) +endif + +# Is any configuration missing? +ifeq ($(OS),WNT) +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_timer \ +)) +endif + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Module_add_check_targets,vcl,\ + CppunitTest_vcl_timer \ +)) +endif + +# screenshots +$(eval $(call gb_Module_add_screenshot_targets,vcl,\ + CppunitTest_vcl_dialogs_test \ +)) + +ifneq ($(DISPLAY),) +$(eval $(call gb_Module_add_slowcheck_targets,vcl,\ + CppunitTest_vcl_gen \ +)) +endif + +ifneq (,$(filter PDFIUM,$(BUILD_TYPE))) +$(eval $(call gb_Module_add_slowcheck_targets,vcl,\ + CppunitTest_vcl_pdfexport \ + CppunitTest_vcl_filter_ipdf \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_fontunxppds.mk b/vcl/Package_fontunxppds.mk new file mode 100644 index 000000000..0902bcb42 --- /dev/null +++ b/vcl/Package_fontunxppds.mk @@ -0,0 +1,25 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Package_Package,vcl_fontunxppds,$(SRCDIR)/vcl/unx/generic/printer/configuration/ppds)) + +$(eval $(call gb_Package_add_files,vcl_fontunxppds,$(LIBO_SHARE_FOLDER)/psprint/driver,\ + SGENPRT.PS \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_fontunxpsprint.mk b/vcl/Package_fontunxpsprint.mk new file mode 100644 index 000000000..1ab2a560b --- /dev/null +++ b/vcl/Package_fontunxpsprint.mk @@ -0,0 +1,25 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Package_Package,vcl_fontunxpsprint,$(SRCDIR)/vcl/unx/generic/printer/configuration)) + +$(eval $(call gb_Package_add_files,vcl_fontunxpsprint,$(LIBO_SHARE_FOLDER)/psprint,\ + psprint.conf \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_opengl_blacklist.mk b/vcl/Package_opengl_blacklist.mk new file mode 100644 index 000000000..35dbfcb0b --- /dev/null +++ b/vcl/Package_opengl_blacklist.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_opengl_blacklist,$(SRCDIR)/vcl/opengl)) + +$(eval $(call gb_Package_add_files,vcl_opengl_blacklist,$(LIBO_SHARE_FOLDER)/opengl,\ + opengl_blacklist_windows.xml \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_opengl_shader.mk b/vcl/Package_opengl_shader.mk new file mode 100644 index 000000000..15e3bee1d --- /dev/null +++ b/vcl/Package_opengl_shader.mk @@ -0,0 +1,41 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_opengl_shader,$(SRCDIR)/vcl/opengl/shaders)) + +$(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\ + areaHashCRC64TFragmentShader.glsl \ + areaScaleFastFragmentShader.glsl \ + areaScaleFragmentShader.glsl \ + blendedTextureFragmentShader.glsl \ + blendedTextureVertexShader.glsl \ + dumbVertexShader.glsl \ + diffTextureFragmentShader.glsl \ + greyscaleFragmentShader.glsl \ + invert50FragmentShader.glsl \ + convolutionFragmentShader.glsl \ + linearGradientFragmentShader.glsl \ + combinedTextureFragmentShader.glsl \ + combinedTextureVertexShader.glsl \ + combinedFragmentShader.glsl \ + combinedVertexShader.glsl \ + lineFragmentShader.glsl \ + lineVertexShader.glsl \ + maskFragmentShader.glsl \ + maskedTextureVertexShader.glsl \ + maskedTextureFragmentShader.glsl \ + radialGradientFragmentShader.glsl \ + replaceColorFragmentShader.glsl \ + solidFragmentShader.glsl \ + textureFragmentShader.glsl \ + textureVertexShader.glsl \ + transformedTextureVertexShader.glsl \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_osxres.mk b/vcl/Package_osxres.mk new file mode 100644 index 000000000..dfbc35a97 --- /dev/null +++ b/vcl/Package_osxres.mk @@ -0,0 +1,18 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_osxres,$(SRCDIR)/vcl/osx/res)) + +$(eval $(call gb_Package_add_files_with_dir,vcl_osxres,Resources,\ + MainMenu.nib/classes.nib \ + MainMenu.nib/info.nib \ + MainMenu.nib/keyedobjects.nib \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/vcl/Package_skia_blacklist.mk b/vcl/Package_skia_blacklist.mk new file mode 100644 index 000000000..611766eb7 --- /dev/null +++ b/vcl/Package_skia_blacklist.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_skia_blacklist,$(SRCDIR)/vcl/skia)) + +$(eval $(call gb_Package_add_files,vcl_skia_blacklist,$(LIBO_SHARE_FOLDER)/skia,\ + skia_blacklist_vulkan.xml \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_theme_definitions.mk b/vcl/Package_theme_definitions.mk new file mode 100644 index 000000000..395a90b19 --- /dev/null +++ b/vcl/Package_theme_definitions.mk @@ -0,0 +1,57 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_theme_definitions,$(SRCDIR)/vcl/uiconfig/theme_definitions)) + +$(eval $(call gb_Package_add_files_with_dir,vcl_theme_definitions,$(LIBO_SHARE_FOLDER)/theme_definitions,\ + ios/definition.xml \ + ios/switch-off.svg \ + ios/switch-off-disabled.svg \ + ios/switch-off-pressed.svg \ + ios/switch-on.svg \ + ios/switch-on-pressed.svg \ + ios/switch-on-disabled.svg \ + ios/tick-off.svg \ + ios/tick-off-disabled.svg \ + ios/tick-off-pressed.svg \ + ios/tick-on.svg \ + ios/tick-on-pressed.svg \ + ios/tick-on-disabled.svg \ + ios/spinbox-left.svg \ + ios/spinbox-left-pressed.svg \ + ios/spinbox-left-disabled.svg \ + ios/spinbox-right.svg \ + ios/spinbox-right-pressed.svg \ + ios/spinbox-right-disabled.svg \ + ios/common-rect.svg \ + ios/common-rect-disabled.svg \ + ios/common-rect-focus.svg \ + ios/common-rect-focus-slim.svg \ + ios/pushbutton-default.svg \ + ios/pushbutton-rollover.svg \ + ios/pushbutton-disabled.svg \ + ios/tabitem-first.svg \ + ios/tabitem-middle.svg \ + ios/tabitem-last.svg \ + ios/tabitem-first-selected.svg \ + ios/tabitem-middle-selected.svg \ + ios/tabitem-last-selected.svg \ + ios/scrollbar-horizontal.svg \ + ios/scrollbar-vertical.svg \ + ios/combobox.svg \ + ios/combobox-disabled.svg \ + ios/combobox-button.svg \ + ios/combobox-button-disabled.svg \ + ios/arrow-up.svg \ + ios/arrow-down.svg \ + ios/slider-button.svg \ + ios/slider-button-disabled.svg \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Package_tipoftheday.mk b/vcl/Package_tipoftheday.mk new file mode 100644 index 000000000..18a086758 --- /dev/null +++ b/vcl/Package_tipoftheday.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,tipoftheday_images,$(SRCDIR)/extras/source/tipoftheday)) + +$(eval $(call gb_Package_add_files_with_dir,tipoftheday_images,$(LIBO_SHARE_FOLDER)/tipoftheday,\ + tipoftheday.png \ + tipoftheday_w.png \ + tipoftheday_c.png \ + tipoftheday_i.png \ + tipoftheday_d.png \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/README b/vcl/README new file mode 100644 index 000000000..e0944688f --- /dev/null +++ b/vcl/README @@ -0,0 +1,242 @@ +Visual Class Library is responsible for the widgets (windowing, buttons, controls, file-pickers etc.), operating system abstraction, including basic rendering (e.g. the output device). + +It should not be confused with Borland's Visual Component Library, which is entirely unrelated. + +VCL provides a graphical toolkit similar to gtk+, Qt, SWING etc. + +source/ + + the main cross-platform chunk of source + +inc/ + + cross-platform abstraction headers + +headless/ + + a backend renderer that draws to bitmaps + +android/ + + Android backend + +osx/ + + macOS backend + +ios/ + + iOS backend + +quartz/ + + code common to macOS and iOS + +win/ + + Windows backend + +qt5/ + + Qt5 (under construction) + +unx/ + + X11 backend and its sub-platforms + gtk3/ + + GTK3 support + kf5/ + + KF5 support (based on qt5 VCL plugin mentioned above) + gtk3_kde5/ + + GTK3 support with KDE5 file pickers (alternative to native kf5 one) + generic/ + + raw X11 support + + plugadapt/ + + pluggable framework to select correct unx backend + + dtrans/ + + "data transfer" - clipboard handling + + http://stackoverflow.com/questions/3261379/getting-html-source-or-rich-text-from-the-x-clipboard + for tips how to show the current content of the + clipboard + + +How the platform abstraction works + + + InitVCL calls 'CreateSalInstance' + + this is implemented by the compiled-in platform backend + + it stores various bits of global state in the + 'SalData' (inc/saldatabasic.hxx) structure but: + + the SalInstance vtable is the primary outward facing gateway + API for platform backends + + It is a factory for: + SalFrames, SalVirtualDevices, SalPrinters, + Timers, the SolarMutex, Drag&Drop and other + objects, as well as the primary event loop wrapper. + +Note: references to "SV" in the code mean StarView, which was a +portable C++ class library for GUIs, with very old roots, that was +developed by StarDivision. Nowadays it is not used by anything except +LibreOffice (and OpenOffice). + +"svp" stands for "StarView Plugin". + +== COM threading == + +The way COM is used in LO generally: +- vcl puts main thread into Single-threaded Apartment (STA) +- oslWorkerWrapperFunction() puts every thread spawned via oslCreateThread() + into MTA (free-threaded) + +== GDIMetafile == + +GDIMetafile is a vector drawing representation that corresponds directly +to the SVM (StarView Metafile) format; it is extremely important as +an intermediate format in all sorts of drawing and printing operations. + +There is a class MetafileXmlDump in include/vcl/mtfxmldump.hxx that +can store a GDIMetafile as XML, which makes debugging much easier +since you can just use "diff" to see changes. + +== EMF+ == + +emf+ is vector file format used by MSO and is successor of wmf and +emf formats. see +http://msdn.microsoft.com/en-us/library/cc230724.aspx for +documentation. note that we didn't have this documentation from +start, so part of the code predates to the time when we had guessed +some parts and can be enhanced today. there also still many thing not +complete + +emf+ is handled a bit differently compared to original emf/wmf files, +because GDIMetafile is missing features we need (mostly related to +transparency, argb colors, etc.) + +emf/wmf is translated to GDIMetafile in import filter +vcl/source/filter/wmf and so special handling ends here + +emf+ is encapsulated into GDIMetafile inside comment records and +parsed/rendered later, when it reaches cppcanvas. It is parsed and +rendered in cppcanvas/source/mtfrenderer. also note that there are +emf+-only and emf+-dual files. dual files contains both types of +records (emf and emf+) for rendering the images. these can used also +in applications which don't know emf+. in that case we must ignore +emf records and use emf+ for rendering. for more details see +documentation + +parsing: + + wmf/emf filter --> GDI metafile with emf+ in comments --> cppcanvas metafile renderer + +lately the GDIMetafile rendering path changed which also influenced +emf+ rendering. now many things happen in drawing layer, where +GDIMetafile is translated into drawing layer primitives. for +metafiles with emf+ we let the mtfrenderer render them into bitmap +(with transparency) and use this bitmap in drawinlayer. cleaner +solution for current state would be to extend the drawing layer for +missing features and move parsing into drawing layer (might be quite +a lot of work). intermediary enhancement would be to know better the +needed size/resolution of the bitmap, before we render emf+ into +bitmap in drawing layer. Thorsten is working on the same problem with +svg rendering, so hopefully his approach could be extended for emf+ as +well. the places in drawing layer where we use canvas mtfrenderer to +render into bitmaps can be found when you grep for GetUseCanvas. also +look at vcl/source/gdi/gdimetafile.cxx where you can look for +UseCanvas again. moving the parsing into drawinglayer might also have +nice side effect for emf+-dual metafiles. in case the emf+ records +are broken, it would be easier to use the duplicit emf +rendering. fortunately we didn't run into such a broken emf+ file +yet. but there were already few cases where we first though that the +problem might be because of broken emf+ part. so far it always turned +out to be another problem. + +rendering: + + before + + vcl --> cppcanvas metafile renderer --> vcl + + now + + drawing layer --> vcl --> cppcanvas metafile renderer --> vcl --> drawing layer + +another interesting part is actual rendering into canvas bitmap and +using that bitmap later in code using vcl API. + +EMF+ implementation has some extensive logging, best if you do a dbgutil +build, and then + +export SAL_LOG=+INFO.cppcanvas.emf+INFO.vcl.emf + +before running LibreOffice; it will give you lots of useful hints. + +You can also fallback to EMF (from EMF+) rendering via + +export EMF_PLUS_DISABLE=1 + + +== Printing/PDF export == + +Printing from Writer works like this: + +1) individual pages print by passing an appropriate OutputDevice to XRenderable +2) in drawinglayer, a VclMetafileProcessor2D is used to record everything on + the page (because the OutputDevice has been set up to record a GDIMetaFile) +3) the pages' GDIMetaFiles are converted to PDF by the vcl::PDFWriter + in vcl/source/gdi/pdfwriter* + +Creating the ODF thumbnail for the first page works as above except step 3 is: + +3) the GDIMetaFile is replayed to create the thumbnail + +On-screen display differs in step 1 and 2: + +1) the VCL Window gets invalidated somehow and paints itself +2) in drawinglayer, a VclPixelProcessor2D is used to display the content + + +=== Debugging PDF export === + +Debugging the PDF export becomes much easier when +compression is disabled (so the PDF file is directly readable) and +the MARK function puts comments into the PDF file about which method +generated the following PDF content. + +The compression can be disabled even using an env. var: + +export VCL_DEBUG_DISABLE_PDFCOMPRESSION=1 + +To de-compress the contents of a PDF file written by a release build or +other programs, use the "pdfunzip" tool: + +bin/run pdfunzip input.pdf output.pdf + +=== SolarMutexGuard === + +The solar mutex is the "big kernel lock" of LibreOffice, a global one. It's a +recursive mutex, so it's allowed to take the lock on the same thread multiple +times, and only the last unlock will actually release the mutex. + +UNO methods on components can be called from multiple threads, while the +majority of the codebase is not prepared for multi-threading. One way to get +around this mismatch is to create a SolarMutexGuard instance at the start of +each & every UNO method implementation, but only when it is necessary: + +- Only acquire the SolarMutex if you actually need it (e.g., not in functions + that return static information). + +- Only around the code that actually needs it (i.e., never call out with it + locked). + +This way you ensure that code (not prepared for multithreading) is still +executed only on a single thread. + +In case you expect that your caller takes the solar mutex, then you can use +the DBG_TESTSOLARMUTEX() macro to assert that in dbgutil builds. + +Event listeners are a special (but frequent) case of the "never call out with +a mutex (SolarMutex or other) locked" fundamental rule: + +- UNO methods can be called from multiple threads, so most implementations + take the solar mutex as their first action when necessary. + +- This can be problematic if later calling out (an event handler is called), + where the called function may be an UNO method implementation as well and + may be invoked on a different thread. + +- So we try to not own the solar mutex, whenever we call out (invoke event + listeners). + +In short, never hold any mutex unless necessary, especially not when calling +out. diff --git a/vcl/README.GDIMetaFile b/vcl/README.GDIMetaFile new file mode 100644 index 000000000..98be38d08 --- /dev/null +++ b/vcl/README.GDIMetaFile @@ -0,0 +1,190 @@ +GDIMetaFile class +================= + +The GDIMetaFile class reads, writes, manipulates and replays metafiles via the VCL module. + +A typical use case is to initialize a new GDIMetaFile, open the actual stored metafile and +read it in via GDIMetaFile::Read( aIStream ). This reads in the metafile into the GDIMetafile +object - it can read in an old-style VCLMTF metafile (back in the days that Microsoft didn't +document the metafile format this was used), as well as EMF+ files - and adds them to a list +(vector) of MetaActions. You can also populate your own GDIMetaFile via AddAction(), +RemoveAction(), ReplaceAction(), etc. + +Once the GDIMetafile object is read to be used, you can "play" the metafile, pause it, wind +forward or rewind the metafile. The metafile can be moved, scaled, rotated and clipped, as +well have the colours adjusted or replaced, or even made monochrome. + +The GDIMetafile can be used to get an OutputDevice's metafile via the Linker() and Record() +functions. + + +Using GDIMetafile +----------------- + +First, create a new GDIMetafile, this can be done via the default constructor. It can then +be constructed manually, or you can use Record() on an OutputDevice to populate the +GDIMetaFile, or of course you can read it from file with Read(). From here you can then +elect to manipulate the metafile, or play it back to another GDIMetafile or to an +OutputDevice via Play(). To store the file, use Write(). + +CONSTRUCTORS AND DESTRUCTORS + +- GDIMetaFile +- GDIMetaFile( cosnt GDIMetaFile& rMtf ) - copy constructor +- ~GDIMetaFile + + +OPERATORS + +- operator = +- operator == +- operator != + + +RECORDING AND PLAYBACK FUNCTIONS + +- Play(GDIMetaFile&, size_t) - play back metafile into another metafile up + to position +- Play(OutputDevice*, size_t) - play back metafile into OutputDevice up to + position +- Play(OutputDevice*, Point, Size, size_t) - play back metafile into OutputDevice at a + particular location on the OutputDevice, up + to the position in the metafile +- Pause - pauses or continues the playback +- IsPause +- Stop - stop playback fully +- WindStart - windback to start of the metafile +- windPrev - windback one record +- GetActionSize - get the number of records in the metafile + + +METAFILE RECORD FUNCTIONS + +- FirstAction - get the first metafile record +- NextAction - get the next metafile record from the + current position +- GetAction(size_t) - get the metafile record at location in file +- GetCurAction - get the current metafile record +- AddAction(MetaAction*) - appends a metafile record +- AddAction(MetaAction*, size_t) - adds a metafile record to a particular + location in the file +- RemoveAction - removes record at file location +- Clear - first stops if recording, then removes all + metafile records +- push_back - pushes back, basically a thin wrapper to the + metafile record list + + +READ AND WRITING + +- Read +- Write +- GetChecksum +- GetSizeBytes + + +DISPLACEMENT FUNCTIONS + +- Move( long nX, long nX) +- Move( long nX, long nX, long nDPIX, long nDPIY ) - Move method getting specifics how to + handle MapMode( MapUnit::MapPixel ) + + +TRANSFORMATION FUNCTIONS + +- Scale( double fScaleX, double fScaleY ) +- Scale( const Fraction& rScaleX, const Fraction& rScaleY ) +- Mirror +- Rotate( long nAngle10 ) +- Clip( const Rectangle& ) + + +COLOR ADJUSTMENT FUNCTIONS + +- Adjust - change luminance, contrast, gamma and RGB via a + percentage +- Convert - colour conversion +- ReplaceColors +- GetMonochromeMtf + + +Related classes +--------------- + +MetaAction: a base class used by all records. It implements a command-like pattern, and also +acts as a prototype for other actions. + + +CONSTRUCTORS AND DESTRUCTORS + +- MetaAction() - default constructor, sets mnRefCount to 1 and + mnType, in this case MetaActionType::NONE +- MetaAction(sal_uInt16 nType) - virtual constructor, sets mnType to nType, and + mnRefCount to 1 +- ~MetaAction + + +COMMAND FUNCTION + +- Execute(OutputDevice*) - execute the functionality of the record to the + OutputDevice. Part of command pattern. + + +FACTORY FUNCTION + +- Clone() - prototype clone function + + +MANIPULATION FUNCTIONS + +- Move(long nHorzMove, long nVerMove) +- Scale(double fScaleX, double fScaleY) + + +READ AND WRITE FUNCTIONS + +- Read +- Write +- ReadMetaAction - a static function, only used to determine which + MetaAction to call on to read the record, which + means that this is the function that must be used. + + +INTROSPECTIVE FUNCTIONS + +- GetType + + + +A note about MetaCommentAction: +------------------------------- + +So this class is the most interesting - a comment record is what is used to extended metafiles, to +make what we call an "Enhanced Metafile". This basically gets the OutputDevice's connect metafile +and adds the record via this when it runs Execute(). It doesn't actually do anything else, unlike +other MetaActions which invoke functions from OutputDevice. And if there is no connect metafile in +OutputDevice, then it just does nothing at all in Execute. Everything else works as normal (Read, +Write, etc). + + + +Basic pseudocode +---------------- + +The following illustrates an exceptionally basic and incomplete implementation of how to use +GDIMetafile. An example can be found at vcl/workben/mtfdemo.cxx + + +DemoWin::Paint() +{ + // assume that VCL has been initialized and a new application created + + Window* pWin = new WorkWindow(); + GDIMetaFile* pMtf = new GDIMetaFile(); + + SvFileStream aFileStream("example.emf", STEAM_READ); + + ReadWindowMetafile(aFileStream, pMtf); + pMtf->Play(pWin); + +} diff --git a/vcl/README.lifecycle b/vcl/README.lifecycle new file mode 100644 index 000000000..a309b65ef --- /dev/null +++ b/vcl/README.lifecycle @@ -0,0 +1,325 @@ +** Understanding transitional VCL lifecycle ** + +---------- How it used to look ---------- + + All VCL classes were explicitly lifecycle managed; so you would +do: + Dialog aDialog(...); // old - on stack allocation + aDialog.Execute(...); +or: + Dialog *pDialog = new Dialog(...); // old - manual heap allocation + pDialog->Execute(...); + delete pDialog; +or: + std::shared_ptr xDialog(new pDialog()); // old + xDialog->Execute(...); + // depending who shared the ptr this would be freed sometime + + In several cases this lead to rather unpleasant code, when +various shared_ptr wrappers were used, the lifecycle was far less than +obvious. Where controls were wrapped by other ref-counted classes - +such as UNO interfaces, which were also used by native Window +pointers, the lifecycle became extremely opaque. In addition VCL had +significant issues with re-enterancy and event emission - adding +various means such as DogTags to try to detect destruction of a window +between calls: + + ImplDelData aDogTag( this ); // 'orrible old code + Show( true, ShowFlags::NoActivate ); + if( !aDogTag.IsDead() ) // did 'this' go invalid yet ? + Update(); + + Unfortunately use of such protection is/was ad-hoc, and far +from uniform, despite the prevalence of such potential problems. + + When a lifecycle problem was hit, typically it would take the +form of accessing memory that had been freed, and contained garbage due +to lingering pointers to freed objects. + + +---------- Where we are now: ---------- + + To fix this situation we now have a VclPtr - which is a smart + reference-counting pointer (include/vcl/vclptr.hxx) which is + designed to look and behave -very- much like a normal pointer + to reduce code-thrash. VclPtr is used to wrap all OutputDevice + derived classes thus: + + VclPtr pDialog( new Dialog( ... ), SAL_NO_ACQUIRE ); + ... + pDialog.disposeAndClear(); + + However - while the VclPtr reference count controls the + lifecycle of the Dialog object, it is necessary to be able to + break reference count cycles. These are extremely common in + widget hierarchies as each widget holds (smart) pointers to + its parents and also its children. + + Thus - all previous 'delete' calls are replaced with 'dispose' + method calls: + +** What is dispose ? + + Dispose is defined to be a method that releases all references + that an object holds - thus allowing their underlying + resources to be released. However - in this specific case it + also releases all backing graphical resources. In practical + terms, all destructor functionality has been moved into + 'dispose' methods, in order to provide a minimal initial + behavioral change. + + As such a VclPtr can have three states: + + VclPtr pButton; + ... + assert (pButton == nullptr || !pButton); // null + assert (pButton && !pButton->IsDisposed()); // alive + assert (pButton && pButton->IsDisposed()); // disposed + +** ScopedVclPtr - making disposes easier + + While replacing existing code with new, it can be a bit + tiresome to have to manually add 'disposeAndClear()' + calls to VclPtr<> instances. + + Luckily it is easy to avoid that with a ScopedVclPtr which + does this for you when it goes out of scope. + +** One extra gotcha - an initial reference-count of 1 + + In the normal world of love and sanity, eg. creating UNO + objects, the objects start with a ref-count of zero. Thus + the first reference is always taken after construction by + the surrounding smart pointer. + + Unfortunately, the existing VCL code is somewhat tortured, + and does a lot of reference and de-reference action on the + class -during- construction. This forces us to construct with + a reference of 1 - and to hand that into the initial smart + pointer with a SAL_NO_ACQUIRE. + + To make this easier, we have 'Instance' template wrappers + that make this apparently easier, by constructing the + pointer for you. + +** How does my familiar code change ? + + Lets tweak the exemplary code above to fit the new model: + +- Dialog aDialog(... dialog params ... ); +- aDialog.Execute(...); ++ ScopedVclPtrInstance pDialog(... dialog params ... ); ++ pDialog->Execute(...); // VclPtr behaves much like a pointer + +or: +- Dialog *pDialog = new Dialog(... dialog params ...); ++ VclPtrInstance pDialog(... dialog params ...); + pDialog->Execute(...); +- delete pDialog; ++ pDialog.disposeAndClear(); // done manually - replaces a delete +or: +- std::shared_ptr xDialog(new Dialog(...)); ++ ScopedVclPtrInstance xDialog(...); + xDialog->Execute(...); ++ // depending how shared_ptr was shared perhaps ++ // someone else gets a VclPtr to xDialog +or: +- VirtualDevice aDev; ++ ScopedVclPtrInstance pDev; + + Other things that are changed are these: + +- pButton = new PushButton(NULL); ++ pButton = VclPtr::Create(nullptr); +... +- vcl::Window *pWindow = new PushButton(NULL); ++ VclPtr pWindow; ++ pWindow.reset(VclPtr::Create(nullptr)); + +** Why are these 'disposeOnce' calls in destructors ? + + This is an interim measure while we are migrating, such that + it is possible to delete an object conventionally and ensure + that its dispose method gets called. In the 'end' we would + instead assert that a Window has been disposed in its + destructor, and elide these calls. + + As the object's vtable is altered as we go down the + destruction process, and we want to call the correct dispose + methods we need this disposeOnce(); call for the interim in + every destructor. This is enforced by a clang plugin. + + The plus side of disposeOnce is that the mechanics behind it + ensure that a dispose() method is only called a single time, + simplifying their implementation. + + +---------- Who owns & disposes what ? ---------- + + Window sub-classes tend to create their widgets in one of two +ways and often both. + + 1. Derive from VclBuilderContainer. The VclBuilder then owns + many of the sub-windows, which are fetched by a 'get' + method into local variables often in constructors eg. + + VclPtr mpButton; // in the class + , get(mpButton, "buttonName") // in the constructor + mpButton.clear(); // in dispose. + + We only clear, not disposeAndClear() in our dispose method + for this case, since the VclBuilder / Container truly owns + this Window, and needs to dispose its hierarchy in the + right order - first children then parents. + + 2. Explicitly allocated Windows. These are often created and + managed by custom widgets: + + VclPtr mpComplex; // in the class + , mpComplex( VclPtr::Create( this ) ) // constructor + mpComplex.disposeAndClear(); // in dispose + + ie. an owner has to dispose things they explicitly allocate. + + In order to ensure that the VclBuilderConstructor + sub-classes have their Windows disposed at the correct time + there is a disposeBuilder(); method - that should be added + -only- to the class immediately deriving from + VclBuilderContainer's dispose. + +---------- What remains to be done ? ---------- + + * Cleanup DogTags + + * Expand the VclPtr pattern to many other less + than safe VCL types. + + * create factory functions for VclPtr<> types and privatize + their constructors. + + * Pass 'const VclPtr<> &' instead of pointers everywhere + + add 'explicit' keywords to VclPtr constructors to + accelerate compilation etc. + + * Cleanup common existing methods such that they continue to + work post-dispose. + + * Dispose functions should be audited to: + + not leave dangling pointsr + + shrink them - some work should incrementally + migrate back to destructors. + + * VclBuilder + + ideally should keep a reference to pointers assigned + in 'get()' calls - to avoid needing explicit 'clear' + code in destructors. + + * VclBuilder 'makeFoo' methods + + these should return VclPtr<> types and have their + signatures adjusted en-masse. + + currently we use a VclPtr<> constructor with + SAL_NO_ACQUIRE inside the builder. + +---------- FAQ / debugging hints ---------- + +** Compile with dbgutil + + This is by far the best way to turn on debugging and + assertions that help you find problems. In particular + there are a few that are really helpful: + + vcl/source/window/window.cxx (Window::dispose) + "Window ( N4sfx27sidebar20SidebarDockingWindowE (Properties)) + ^^^ class name window title ^^^ + with live children destroyed: N4sfx27sidebar6TabBarE () + N4sfx27sidebar4DeckE () 10FixedImage ()" + + You can de-mangle these names if you can't read them thus: + + $ c++filt -t N4sfx27sidebar20SidebarDockingWindowE + sfx2::sidebar::SidebarDockingWindow + + In the above case - it is clear that the children have not been + disposed before their parents. As an aside, having a dispose chain + separate from destructors allows us to emit real type names for + parents here. + + To fix this, we will need to get the dispose ordering right, + occasionally in the conversion we re-ordered destruction, or + omitted a disposeAndClear() in a ::dispose() method. + + => If you see this, check the order of disposeAndClear() in + the sfx2::Sidebar::SidebarDockingWindow::dispose() method + + => also worth git grepping for 'new sfx::sidebar::TabBar' to + see where those children were added. + +** Check what it used to do + + While a ton of effort has been put into ensuring that the new + lifecycle code is the functional equivalent of the old code, + the code was created by humans. If you identify an area where + something asserts or crashes here are a few helpful heuristics: + + * Read the git log -u -- path/to/file.cxx + + => Is the order of destruction different ? + + in the past many things were destructed (in reverse order of + declaration in the class) without explicit code. Some of these + may be important to do explicitly at the end of the destructor. + + eg. having a 'Idle' or 'Timer' as a member, may now need an + explicit .Stop() and/or protection from running on a + disposed Window in its callback. + + => Is it 'clear' not 'disposeAndClear' ? + + sometimes we get this wrong. If the code previously used to + use 'delete pFoo;' it should now read pFoo->disposeAndClear(); + Conversely if it didn't delete it, it should be 'clear()' it + is by far the best to leave disposing to the VclBuilder where + possible. + + In simple cases, if we allocate the widget with VclPtrInstance + or VclPtr::Create - then we need to disposeAndClear it too. + +** Event / focus / notification ordering + + In the old world, a large amount of work was done in the + ~Window destructor that is now done in Window::dispose. + + Since those Windows were in the process of being destroyed + themselves, their vtables were adjusted to only invoke Window + methods. In the new world, sub-classed methods such as + PreNotify, GetFocus, LoseFocus and others are invoked all down + the inheritance chain from children to parent, during dispose. + + The easiest way to fix these is to just ensure that these + cleanup methods, especially LoseFocus, continue to work even + on disposed Window sub-class instances. + +** It crashes with some invalid memory... + + Assuming that the invalid memory is a Window sub-class itself, + then almost certainly there is some cockup in the + reference-counting; eg. if you hit an OutputDevice::release + assert on mnRefCount - then almost certainly you have a + Window that has already been destroyed. This can easily + happen via this sort of pattern: + + Dialog *pDlg = VclPtr(nullptr /* parent */); + // by here the pDlg quite probably points to free'd memory... + + It is necessary in these cases to ensure that the *pDlg is + a VclPtr instead. + +** It crashes with some invalid memory #2... + + Often a ::dispose method will free some pImpl member, but + not NULL it; and (cf. above) we can now get various virtual + methods called post-dispose; so: + + a) delete pImpl; pImpl = NULL; // in the destructor + b) if (pImpl && ...) // in the subsequently called method + diff --git a/vcl/README.scheduler b/vcl/README.scheduler new file mode 100644 index 000000000..52c76dac5 --- /dev/null +++ b/vcl/README.scheduler @@ -0,0 +1,394 @@ += Introduction = + +The VCL scheduler handles LOs primary event queue. It is simple by design, +currently just a single-linked list, processed in list-order by priority +using round-robin for reoccurring tasks. + +The scheduler has the following behaviour: + +B.1. Tasks are scheduled just priority based +B.2. Implicitly cooperative AKA non-preemptive +B.3. It's not "fair" in any way (a consequence of B.2) +B.4. Tasks are handled round-robin (per priority) +B.5. Higher priorities have lower values +B.6. A small set of priorities instead of an flexible value AKA int + +There are some consequences due to this design. + +C.1. Higher priority tasks starve lower priority tasks + As long as a higher task is available, lower tasks are never run! + See Anti-pattern. + +C.2. Tasks should be split into sensible blocks + If this can't really be done, process pending tasks by calling + Application::Reschedule(). Or use a thread. + +C.3. This is not an OS scheduler + There is no real way to "fix" B.2. and B.3. + If you need to do a preemptive task, use a thread! + Otherwise make your task suspendable. + + += Driving the scheduler AKA the system timer = + + 1. There is just one system timer, which drives LO event loop + 2. The timer has to run in the main window thread + 3. The scheduler is run with the Solar mutex acquired + 4. The system timer is a single-shot timer + 5. The scheduler system event / message has a low system priority. + All system events should have a higher priority. + +Every time a task is started, the scheduler timer is adjusted. When the timer +fires, it posts an event to the system message queue. If the next most +important task is an Idle (AKA instant, 0ms timeout), the event is pushed to +the back of the queue, so we don't starve system messages, otherwise to the +front. + +Every time the scheduler is invoked it searches for the next task to process, +restarts the timer with the timeout for the next event and then invokes the +task. After invoking the task and if the task is still active, it is pushed +to the end of the queue and the timeout is eventually adjusted. + + += Locking = + +The locking is quite primitive: all interaction with internal Scheduler +structures are locked. This includes the ImplSchedulerContext and the +Task::mpSchedulerData, which is actually a part of the scheduler. +Before invoking the task, we have to release the lock, so others can +Start new Tasks. + + += Lifecycle / thread-safety of Scheduler-based objects = + +A scheduler object it thread-safe in the way, that it can be associated to +any thread and any thread is free to call any functions on it. The owner must +guarantee that the Invoke() function can be called, while the Scheduler object +exists / is not disposed. + + += Anti-pattern: Dependencies via (fine grained) priorities = + +"Idle 1" should run before "Idle 2", therefore give "Idle 1" a higher priority +then "Idle 2". This just works correct for low frequency idles, but otherwise +always breaks! + +If you have some longer work - even if it can be split by into schedulable, +smaller blocks - you normally don't want to schedule it with a non-default +priority, as it starves all lower priority tasks. Even if a block was processed +in "Idle 1", it is scheduled with the same (higher) priority again. Changing +the "Idle" to a "Timer" also won't work, as this breaks the dependency. + +What is needed is task based dependency handling, so if "Task 1" is done, it +has to start "Task 2" and if "Task 1" is started again, it has to stop +"Task 2". This currently has to be done by the implementor, but this feature +can be added to the scheduler reasonably. + + += Implementation details = + +== General: event priority for DoYield == + +There are three types of events, with different priority: + +1. LO user events +2. System events +3. LO Scheduler event + +They should be processed according to the following code: + +bool DoYield( bool bWait, bool bAllCurrent ) +{ + bool bWasEvent = ProcessUserEvents( bAllCurrent ); + if ( !bAllCurrent && bWasEvent ) + return true; + bWasEvent = ProcessSystemEvents( bAllCurrent, &bWasSchedulerEvent ) || bWasEvent; + if ( !bWasSchedulerEvent && IsSchedulerEvent() ) + { + ProcessSchedulerEvent() + bWasEvent = true; + } + if ( !bWasEvent && bWait ) + { + WaitForSystemEvents(); + bWasEvent = true; + } + return bWasEvent; +} + +== General: main thread deferral == + +In almost all VCL backends, we run main thread deferrals by disabling the +SolarMutex using a boolean. In the case of the redirect, this makes +tryToAcquire and doAcquire return true or 1, while a release is ignored. +Also the IsCurrentThread() mutex check function will act accordingly, so all +the DBG_TESTSOLARMUTEX won't fail. + +Since we just disable the locks when we start running the deferred code in the +main thread, we won't let the main thread run into stuff, where it would +normally wait for the SolarMutex. + +Eventually this will move into the SolarMutex. KDE / Qt also does main +thread redirects using Qt::BlockingQueuedConnection. + +== General: processing all current events for DoYield == + +This is easily implemented for all non-priority queue based implementations. +Windows and macOS both have a timestamp attached to their events / messages, +so simply get the current time and just process anything < timestamp. +For the KDE backend this is already the default behaviour - single event +processing isn't even supported. The headless backend accomplishes this by +just processing a copy of the list of current events. + +Problematic in this regard is the Gtk+ backend. g_main_context_iteration +dispatches "only those highest priority event sources". There is no real way +to tell, when these became ready. I've added a workaround idea to the TODO +list. FWIW: Qt runs just a single timer source in the glib main context, +basically the same we're doing with the LO scheduler as a system event. + +The gen X11 backend has some levels of redirection, but needs quite some work +to get this fixed. + +== General: non-main thread yield == + +Yielding from a non-main thread must not wait in the main thread, as this +may block the main thread until some events happen. + +Currently we wait on an extra conditional, which is cleared by the main event +loop. + +== General: invalidation of elapsed timer event messages == + +Since the system timer to run the scheduler is single-shot, there should never +be more than one elapsed timer event in system event queue. When stopping or +restarting the timer, we eventually have to remove the now invalid event from +the queue. + +But for the Windows and macOS backends this may fail as they have delayed +posting of events, so a consecutive remove after a post will actually yield no +remove. On Windows we even get unwanted processing of events outside of the +main event loop, which may call the Scheduler, as timer management is handled +in critical scheduler code. + +To prevent these problems, we don't even try to remove these events, but +invalidate them by versioning the timer events. Timer events with invalid +versions are processed but simply don't run the scheduler. + +== General: track time of long running tasks == + +There is TaskStopwatch class. It'll track the time and report a timeout either +when the tasks time slice is finished or some system event did occur. + +Eventually it will be merged into the main scheduler, so each invoked task can +easily track it's runtime and eventually this can be used to "blame" / find +other long running tasks, so interactivity can be improved. + +There were some questions coming up when implementing it: + +=== Why does the scheduler not detect that we only have idle tasks pending, +and skip the instant timeout? === + +You never know how long a task will run. Currently the scheduler simply asks +each task when it'll be ready to run, until two runnable tasks are found. +Normally this is very quick, as LO has a lot of one-shot instant tasks / Idles +and just a very few long term pending Timers. + +Especially UNO calls add a lot of Idles to the task list, which just need to +be processed in order. + +=== Why not use things like Linux timer wheels? === + +LO has relatively few timers and a lot one-shot Idles. 99% of time the search +for the next task is quick, because there are just ~5 long term timers per +document (cache invalidation, cursor blinking etc.). + +This might become a problem, if you have a lot of open documents, so the long +term timer list increases AKA for highly loaded LOOL instances. + +But the Linux timer wheel mainly relies on the facts that the OS timers are +expected to not expire, as they are use to catch "error" timeouts, which rarely +happen, so this definitely not matches LO's usage. + +=== Not really usable to find misbehaving tasks === + +The TaskStopwatch class is just a little time keeper + detecting of input +events. This is not about misbehaving Tasks, but long running tasks, which +have to yield to the Scheduler, so other Tasks and System events can be +processed. + +There is the TODO to merge the functionality into the Scheduler itself, at +which point we can think about profiling individual Tasks to improve +interactivity. + +== macOS implementation details == + +Generally the Scheduler is handled as expected, except on resize, which is +handled with different runloop-modes in macOS. In case of a resize, the normal +runloop is suspended in sendEvent, so we can't call the scheduler via posted +main loop-events. Instead the scheduler uses the timer again. + +Like the Windows backend, all Cocoa / GUI handling also has to be run in +the main thread. We're emulating Windows out-of-order PeekMessage processing, +via a YieldWakeupEvent and two conditionals. When in a RUNINMAIN call, all +the DBG_TESTSOLARMUTEX calls are disabled, as we can't release the SolarMutex, +but we can prevent running any other SolarMutex based code. Those wakeup +events must be ignored to prevent busy-locks. For more info read the "General: +main thread deferral" section. + +We can neither rely on macOS dispatch_sync code block execution nor the +message handling, as both can't be prioritized or filtered and the first +does also not allow nested execution and is just processed in sequence. + +There is also a workaround for a problem for pushing tasks to an empty queue, +as [NSApp postEvent: ... atStart: NO] doesn't append the event, if the +message queue is empty. + +An additional problem is the filtering of events on Window close. This drops +posted timer events, when a Window is closed resulting in a busy DoYield loop, +so we have to re-post the event, after closing a window. + +== Windows implementation details == + +Posted or sent event messages often trigger processing of WndProc in +PeekMessage, GetMessage or DispatchMessage, independently from the message to +fetch, remove or dispatch ("During this call, the system delivers pending, +nonqueued messages..."). Additionally messages have an inherited priority +based on the function used to generate them. Even if WM_TIMER messages should +have the lowest priority, a manually posted WM_TIMER is processed with the +priority of a PostMessage message. + +So we're giving up on processing all our Scheduler events as a message in the +system message loop. Instead we just indicate a 0ms timer message by setting +the m_bDirectTimeout in the timer object. This timer is always processed, if +the system message wasn't already our timer. As a result we can also skip the +polling. All this is one more reason to drop the single message processing +in favour of always processing all pending (system) events. + +There is another special case, we have to handle: window updates during move +and resize of windows. These system actions run in their own nested message +loop. So we have to completely switch to timers, even for 0ms. But these +posted events prevent any event processing, while we're busy. The only viable +solution seems to be to switch to WM_TIMER based timers, as these generate +messages with the lowest system priority (but they don't allow 0ms timeouts). +So processing slows down during resize and move, but we gain working painting, +even when busy. + +An additional workaround is implemented for the delayed queuing of posted +messages, where PeekMessage in WinSalTimer::Stop() won't be able remove the +just posted timer callback message. See "General: invalidation of elapsed +timer event messages" for the details. + +To run the required GUI code in the main thread without unlocking the +SolarMutex, we "disable" it. For more infos read the "General: main thread +deferral" section. + +== KDE implementation details == + +This implementation also works as intended. But there is a different Yield +handling, because Qts QAbstractEventDispatcher::processEvents will always +process all pending events. + + += TODOs and ideas = + +== Task dependencies AKA children == + +Every task can have a list of children / a child. + + * When a task is stopped, the children are started. + * When a task is started, the children are stopped. + +This should be easy to implement. + +== Per priority time-sorted queues == + +This would result in O(1) scheduler. It was used in the Linux kernel for some +time (search Ingo Molnar's O(1) scheduler). This can be a scheduling +optimization, which would prevent walking longer event list. But probably the +management overhead would be too large, as we have many one-shot events. + +To find the next task the scheduler just walks the (constant) list of priority +queues and schedules the first ready event of any queue. + +The downside of this approach: Insert / Start / Reschedule(for "auto" tasks) +now need O(log(n)) to find the position in the queue of the priority. + +== Always process all (higher priority) pending events == + +Currently Application::Reschedule() processes a single event or "all" events, +with "all" defined as "100 events" in most backends. This already is ignored +by the KDE backend, as Qt defines its QAbstractEventDispatcher::processEvents +processing all pending events (there are ways to skip event classes, but no +easy way to process just a single event). + +Since the Scheduler is always handled by the system message queue, there is +really no more reasoning to stop after 100 events to prevent LO Scheduler +starvation. + +== Drop static inherited or composed Task objects == + +The sequence of destruction of static objects is not defined. So a static Task +can not be guaranteed to happen before the Scheduler. When dynamic unloading +is involved, this becomes an even worse problem. This way we could drop the +mbStatic workaround from the Task class. + +== Run the LO application in its own thread == + +This would probably get rid of most of the macOS and Windows implementation +details / workarounds, but is quite probably a large amount of work. + +Instead of LO running in the main process / thread, we run it in a 2nd thread +and defer al GUI calls to the main thread. This way it'll hopefully not block +and can process system events. + +That's just a theory - it definitely needs more analysis before even attending +an implementation. + +== Re-evaluate the macOS ImplNSAppPostEvent == + +Probably a solution comparable to the Windows backends delayed PostMessage +workaround using a validation timestamp is better then the current peek, +remove, re-postEvent, which has to run in the main thread. + +Originally I didn't evaluate, if the event is actually lost or just delayed. + +== Drop nMaxEvents from Gtk+ based backends == + +gint last_priority = G_MAXINT; +bool bWasEvent = false; +do { + gint max_priority; + g_main_context_acquire( NULL ); + bool bHasPending = g_main_context_prepare( NULL, &max_priority ); + g_main_context_release( NULL ); + if ( bHasPending ) + { + if ( last_priority > max_priority ) + { + bHasPending = g_main_context_iteration( NULL, bWait ); + bWasEvent = bWasEvent || bHasPending; + } + else + bHasPending = false; + } +} +while ( bHasPending ) + +The idea is to use g_main_context_prepare and keep the max_priority as an +indicator. We cannot prevent running newer lower events, but we can prevent +running new higher events, which should be sufficient for most stuff. + +This also touches user event processing, which currently runs as a high +priority idle in the event loop. + +== Drop nMaxEvents from gen (X11) backend == + +A few layers of indirection make this code hard to follow. The SalXLib::Yield +and SalX11Display::Yield architecture makes it impossible to process just the +current events. This really needs a refactoring and rearchitecture step, which +will also affect the Gtk+ and KDE backend for the user event handling. + +== Merge TaskStopwatch functionality into the Scheduler == + +This way it can be easier used to profile Tasks, eventually to improve LO's +interactivity. diff --git a/vcl/README.vars b/vcl/README.vars new file mode 100644 index 000000000..9f5a10a26 --- /dev/null +++ b/vcl/README.vars @@ -0,0 +1,52 @@ +Environment variables in VCL: + +General +------- +SAL_USE_VCLPLUGIN - use a VCL plugin +SAL_RTL_ENABLED - Enable RTL UI +SAL_NO_NWF - disable native widgets +SAL_FORCEDPI - force a specific DPI (gtk3 & qt5/kf5 plugins only) +SAL_FORCE_HC - force high-contrast mode + +SAL_NO_FONT_LOOKUP - disable font search and fallback and always use a hard-coded font name (for some unit tests) + +LO_COLLECT_UIINFO - enable the uitesting logging, value is expected to be a relative file name that +will be used to write the log under instdir/uitest/. + +VCL_DOUBLEBUFFERING_AVOID_PAINT - don't paint the buffer, useful to see where we do direct painting +VCL_DOUBLEBUFFERING_FORCE_ENABLE - enable double buffered painting +VCL_DOUBLEBUFFERING_ENABLE - enable a safe subset of double buffered painting (currently in Writer, not in any other applications) + +VCL_DEBUG_DISABLE_PDFCOMPRESSION - disable compression in the PDF writer + +Gtk+ +---- + +VCL_GTK3_PAINTDEBUG - in debug builds, if set to 1 then holding down shift+0 forces a redraw event, shift+1 repaints everything, and +shift+2 dumps cairo frames to pngs as /tmp/frame.png + +Bitmap +------ +VCL_NO_THREAD_SCALE - disable threaded bitmap scale +VCL_NO_THREAD_IMPORT - disable threaded bitmap import +EMF_PLUS_DISABLE - use EMF rendering and ignore EMF+ specifics + +OpenGL +------ +SAL_FORCEGL - force enable OpenGL +SAL_GL_NO_SWAP - disable buffer swapping if set (should show nothing) +SAL_GL_SLEEP_ON_SWAP - sleep for half a second on each swap-buffers. +SAL_DISABLE_WATCHDOG - don't start the thread that watches for broken GL/Vulkan/OpenCL drivers + +Skia +---- +SAL_DISABLESKIA=1 - force disabled Skia +SAL_ENABLESKIA=1 - enable Skia, unless blacklisted (and if the VCL backend supports Skia) +SAL_FORCESKIA=1 - force using Skia, even if blacklisted +SAL_SKIA=raster|vulkan - select Skia's drawing method, by default Vulkan is used +SAL_DISABLE_SKIA_CACHE=1 - disable caching of complex images + +OpenGL,Skia +----------- +SAL_WITHOUT_WIDGET_CACHE - disable LRU caching of native widget textures +SAL_DISABLE_GLYPH_CACHING - don't render glyphs through OpenGL textures or Skia surfaces diff --git a/vcl/StaticLibrary_fuzzer_calc.mk b/vcl/StaticLibrary_fuzzer_calc.mk new file mode 100644 index 000000000..5bb543f56 --- /dev/null +++ b/vcl/StaticLibrary_fuzzer_calc.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzer_calc)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzer_calc,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzer_calc,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_generated_exception_objects,fuzzer_calc,\ + CustomTarget/vcl/workben/native-calc \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_fuzzer_core.mk b/vcl/StaticLibrary_fuzzer_core.mk new file mode 100644 index 000000000..6fa58b10b --- /dev/null +++ b/vcl/StaticLibrary_fuzzer_core.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzer_core)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzer_core,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzer_core,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_generated_exception_objects,fuzzer_core,\ + CustomTarget/vcl/workben/native-core \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_fuzzer_draw.mk b/vcl/StaticLibrary_fuzzer_draw.mk new file mode 100644 index 000000000..69c2cd5ab --- /dev/null +++ b/vcl/StaticLibrary_fuzzer_draw.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzer_draw)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzer_draw,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzer_draw,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_generated_exception_objects,fuzzer_draw,\ + CustomTarget/vcl/workben/native-draw \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_fuzzer_math.mk b/vcl/StaticLibrary_fuzzer_math.mk new file mode 100644 index 000000000..ba5d03889 --- /dev/null +++ b/vcl/StaticLibrary_fuzzer_math.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzer_math)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzer_math,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzer_math,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_generated_exception_objects,fuzzer_math,\ + CustomTarget/vcl/workben/native-math \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_fuzzer_writer.mk b/vcl/StaticLibrary_fuzzer_writer.mk new file mode 100644 index 000000000..91765353f --- /dev/null +++ b/vcl/StaticLibrary_fuzzer_writer.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzer_writer)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzer_writer,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzer_writer,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_generated_exception_objects,fuzzer_writer,\ + CustomTarget/vcl/workben/native-writer \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_fuzzerstubs.mk b/vcl/StaticLibrary_fuzzerstubs.mk new file mode 100644 index 000000000..7d8105906 --- /dev/null +++ b/vcl/StaticLibrary_fuzzerstubs.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_StaticLibrary_StaticLibrary,fuzzerstubs)) + +$(eval $(call gb_StaticLibrary_set_include,fuzzerstubs,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,fuzzerstubs,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_exception_objects,fuzzerstubs,\ + vcl/workben/localestub/localestub \ + vcl/workben/localestub/localedata_en_AU \ + vcl/workben/localestub/localedata_en_BW \ + vcl/workben/localestub/localedata_en_BZ \ + vcl/workben/localestub/localedata_en_CA \ + vcl/workben/localestub/localedata_en_GB \ + vcl/workben/localestub/localedata_en_GH \ + vcl/workben/localestub/localedata_en_GM \ + vcl/workben/localestub/localedata_en_IE \ + vcl/workben/localestub/localedata_en_IN \ + vcl/workben/localestub/localedata_en_JM \ + vcl/workben/localestub/localedata_en_LK \ + vcl/workben/localestub/localedata_en_MW \ + vcl/workben/localestub/localedata_en_MY \ + vcl/workben/localestub/localedata_en_NA \ + vcl/workben/localestub/localedata_en_NG \ + vcl/workben/localestub/localedata_en_NZ \ + vcl/workben/localestub/localedata_en_PH \ + vcl/workben/localestub/localedata_en_TT \ + vcl/workben/localestub/localedata_en_US \ + vcl/workben/localestub/localedata_en_ZA \ + vcl/workben/localestub/localedata_en_ZM \ + vcl/workben/localestub/localedata_en_ZW \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_glxtest.mk b/vcl/StaticLibrary_glxtest.mk new file mode 100644 index 000000000..1a285875c --- /dev/null +++ b/vcl/StaticLibrary_glxtest.mk @@ -0,0 +1,41 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_StaticLibrary_StaticLibrary,glxtest)) + +$(eval $(call gb_StaticLibrary_set_include,glxtest,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,glxtest,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_libs,glxtest,\ + -lm $(DLOPEN_LIBS) \ + -lX11 \ +)) + +$(eval $(call gb_StaticLibrary_add_exception_objects,glxtest,\ + vcl/unx/glxtest \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/StaticLibrary_vclmain.mk b/vcl/StaticLibrary_vclmain.mk new file mode 100644 index 000000000..cc283cc0d --- /dev/null +++ b/vcl/StaticLibrary_vclmain.mk @@ -0,0 +1,42 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_StaticLibrary_StaticLibrary,vclmain)) + +ifeq ($(OS),iOS) +$(eval $(call gb_StaticLibrary_add_cxxflags,vclmain,\ + $(gb_OBJCXXFLAGS) \ +)) +endif + +$(eval $(call gb_StaticLibrary_set_include,vclmain,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_StaticLibrary_use_api,vclmain,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_StaticLibrary_add_exception_objects,vclmain,\ + vcl/source/salmain/salmain \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/UIConfig_vcl.mk b/vcl/UIConfig_vcl.mk new file mode 100644 index 000000000..7941303b6 --- /dev/null +++ b/vcl/UIConfig_vcl.mk @@ -0,0 +1,34 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,vcl)) + +$(eval $(call gb_UIConfig_add_uifiles,vcl,\ + vcl/uiconfig/ui/aboutbox \ + vcl/uiconfig/ui/combobox \ + vcl/uiconfig/ui/cupspassworddialog \ + vcl/uiconfig/ui/editmenu \ + vcl/uiconfig/ui/errornocontentdialog \ + vcl/uiconfig/ui/errornoprinterdialog \ + vcl/uiconfig/ui/moreoptionsdialog \ + vcl/uiconfig/ui/printdialog \ + vcl/uiconfig/ui/printerdevicepage \ + vcl/uiconfig/ui/printerpaperpage \ + vcl/uiconfig/ui/printerpropertiesdialog \ + vcl/uiconfig/ui/printprogressdialog \ + vcl/uiconfig/ui/querydialog \ + vcl/uiconfig/ui/screenshotparent \ + vcl/uiconfig/ui/wizard \ +)) + +$(eval $(call gb_UIConfig_add_a11yerrors_uifiles,vcl,\ + vcl/qa/cppunit/builder/demo \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/WinResTarget_vcl.mk b/vcl/WinResTarget_vcl.mk new file mode 100644 index 000000000..f7195b432 --- /dev/null +++ b/vcl/WinResTarget_vcl.mk @@ -0,0 +1,97 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_WinResTarget_WinResTarget,vcl/salsrc)) + +$(eval $(call gb_WinResTarget_set_include,vcl/salsrc,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ +)) + +$(eval $(call gb_WinResTarget_set_rcfile,vcl/salsrc,\ + vcl/win/src/salsrc \ +)) +$(eval $(call gb_WinResTarget_add_dependencies,vcl/salsrc,\ + vcl/win/src/dtext.cur \ + vcl/win/src/50.bmp \ + vcl/win/src/copydata.cur \ + vcl/win/src/dpie.cur \ + vcl/win/src/movedata.cur \ + vcl/win/src/rotate.cur \ + vcl/win/src/50.png \ + vcl/win/src/copydlnk.cur \ + vcl/win/src/dpolygon.cur \ + vcl/win/src/movedlnk.cur \ + vcl/win/src/salsrc.rc \ + vcl/win/src/copyf.cur \ + vcl/win/src/drect.cur \ + vcl/win/src/movef.cur \ + vcl/win/src/ase.cur \ + vcl/win/src/copyf2.cur \ + vcl/win/src/dtext.cur \ + vcl/win/src/movef2.cur \ + vcl/win/src/tblsele.cur \ + vcl/win/src/asn.cur \ + vcl/win/src/copyflnk.cur \ + vcl/win/src/fill.cur \ + vcl/win/src/moveflnk.cur \ + vcl/win/src/tblsels.cur \ + vcl/win/src/asne.cur \ + vcl/win/src/crook.cur \ + vcl/win/src/movept.cur \ + vcl/win/src/tblselse.cur \ + vcl/win/src/asns.cur \ + vcl/win/src/crop.cur \ + vcl/win/src/tblselsw.cur \ + vcl/win/src/asnswe.cur \ + vcl/win/src/hshear.cur \ + vcl/win/src/tblselw.cur \ + vcl/win/src/asnw.cur \ + vcl/win/src/darc.cur \ + vcl/win/src/nullptr.cur \ + vcl/win/src/ass.cur \ + vcl/win/src/dbezier.cur \ + vcl/win/src/asse.cur \ + vcl/win/src/dcapt.cur \ + vcl/win/src/vshear.cur \ + vcl/win/src/assw.cur \ + vcl/win/src/dcirccut.cur \ + vcl/win/src/linkdata.cur \ + vcl/win/src/pivotcol.cur \ + vcl/win/src/asw.cur \ + vcl/win/src/dconnect.cur \ + vcl/win/src/linkf.cur \ + vcl/win/src/pivotdel.cur \ + vcl/win/src/aswe.cur \ + vcl/win/src/dellipse.cur \ + vcl/win/src/magnify.cur \ + vcl/win/src/pivotfld.cur \ + vcl/win/src/chain.cur \ + vcl/win/src/detectiv.cur \ + vcl/win/src/mirror.cur \ + vcl/win/src/pivotrow.cur \ + vcl/win/src/vtext.cur \ + vcl/win/src/chainnot.cur \ + vcl/win/src/dfree.cur \ + vcl/win/src/chart.cur \ + vcl/win/src/dline.cur \ + vcl/win/src/movebw.cur \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/android/androidinst.cxx b/vcl/android/androidinst.cxx new file mode 100644 index 000000000..94e5f4227 --- /dev/null +++ b/vcl/android/androidinst.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOGTAG "LibreOffice/androidinst" +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOGTAG, __VA_ARGS__)) +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOGTAG, __VA_ARGS__)) + +// Horrible hack +static int viewWidth = 1, viewHeight = 1; + +class AndroidSalData : public GenericUnixSalData +{ +public: + explicit AndroidSalData( SalInstance *pInstance ) : GenericUnixSalData( SAL_DATA_ANDROID, pInstance ) {} + virtual void ErrorTrapPush() {} + virtual bool ErrorTrapPop( bool ) { return false; } +}; + +void AndroidSalInstance::GetWorkArea(tools::Rectangle& rRect) +{ + rRect = tools::Rectangle( Point( 0, 0 ), + Size( viewWidth, viewHeight ) ); +} + +AndroidSalInstance *AndroidSalInstance::getInstance() +{ + if (!ImplGetSVData()) + return NULL; + AndroidSalData *pData = static_cast(ImplGetSVData()->mpSalData); + if (!pData) + return NULL; + return static_cast(pData->m_pInstance); +} + +AndroidSalInstance::AndroidSalInstance( std::unique_ptr pMutex ) + : SvpSalInstance( std::move(pMutex) ) +{ + // FIXME: remove when uniPoll & runLoop is the only Android entry point. + int res = (lo_get_javavm())->AttachCurrentThread(&m_pJNIEnv, NULL); + LOGI("AttachCurrentThread res=%d env=%p", res, m_pJNIEnv); +} + +// This is never called on Android until app exit. +AndroidSalInstance::~AndroidSalInstance() +{ + int res = (lo_get_javavm())->DetachCurrentThread(); + LOGI("DetachCurrentThread res=%d", res); + LOGI("destroyed Android Sal Instance"); +} + +bool AndroidSalInstance::AnyInput( VclInputFlags nType ) +{ + if( nType & VclInputFlags::TIMER ) + return CheckTimeout( false ); + + // Unfortunately there is no way to check for a specific type of + // input being queued. That information is too hidden, sigh. + return SvpSalInstance::s_pDefaultInstance->HasUserEvents(); +} + +void AndroidSalInstance::updateMainThread() +{ + int res = (lo_get_javavm())->AttachCurrentThread(&m_pJNIEnv, NULL); + LOGI("updateMainThread AttachCurrentThread res=%d env=%p", res, m_pJNIEnv); + SvpSalInstance::updateMainThread(); +} + +void AndroidSalInstance::releaseMainThread() +{ + int res = (lo_get_javavm())->DetachCurrentThread(); + LOGI("releaseMainThread DetachCurrentThread res=%d", res); + + SvpSalInstance::releaseMainThread(); +} + +class AndroidSalSystem : public SvpSalSystem { +public: + AndroidSalSystem() : SvpSalSystem() {} + virtual ~AndroidSalSystem() {} + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ); +}; + +SalSystem *AndroidSalInstance::CreateSalSystem() +{ + return new AndroidSalSystem(); +} + +class AndroidSalFrame : public SvpSalFrame +{ +public: + AndroidSalFrame( AndroidSalInstance *pInstance, + SalFrame *pParent, + SalFrameStyleFlags nSalFrameStyle ) + : SvpSalFrame(pInstance, pParent, nSalFrameStyle) + { + if (pParent == NULL && viewWidth > 1 && viewHeight > 1) + SetPosSize(0, 0, viewWidth, viewHeight, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); + } + + virtual void GetWorkArea(tools::Rectangle& rRect) + { + AndroidSalInstance::getInstance()->GetWorkArea( rRect ); + } + + virtual void UpdateSettings( AllSettings &rSettings ) + { + // Clobber the UI fonts +#if 0 + psp::FastPrintFontInfo aInfo; + aInfo.m_aFamilyName = "Roboto"; + aInfo.m_eItalic = ITALIC_NORMAL; + aInfo.m_eWeight = WEIGHT_NORMAL; + aInfo.m_eWidth = WIDTH_NORMAL; + psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() ); +#endif + + // FIXME: is 14 point enough ? + vcl::Font aFont( OUString( "Roboto" ), Size( 0, 14 ) ); + + StyleSettings aStyleSet = rSettings.GetStyleSettings(); + aStyleSet.SetAppFont( aFont ); + aStyleSet.SetHelpFont( aFont ); + aStyleSet.SetMenuFont( aFont ); + aStyleSet.SetToolFont( aFont ); + aStyleSet.SetLabelFont( aFont ); + aStyleSet.SetRadioCheckFont( aFont ); + aStyleSet.SetPushButtonFont( aFont ); + aStyleSet.SetFieldFont( aFont ); + aStyleSet.SetIconFont( aFont ); + aStyleSet.SetTabFont( aFont ); + aStyleSet.SetGroupFont( aFont ); + + rSettings.SetStyleSettings( aStyleSet ); + } +}; + +SalFrame *AndroidSalInstance::CreateChildFrame( SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle ) +{ + return new AndroidSalFrame( this, NULL, nStyle ); +} + +SalFrame *AndroidSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) +{ + return new AndroidSalFrame( this, pParent, nStyle ); +} + +void SalAbort( const OUString& rErrorText, bool bDumpCore ) +{ + OUString aError( rErrorText ); + if( aError.isEmpty() ) + aError = "Unknown application error"; + LOGI("%s", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() ); + + LOGI("SalAbort: '%s'", + OUStringToOString(aError, RTL_TEXTENCODING_ASCII_US).getStr()); + if( bDumpCore ) + abort(); + else + _exit(1); +} + +const OUString& SalGetDesktopEnvironment() +{ + static OUString aEnv( "android" ); + return aEnv; +} + +SalData::SalData() : + m_pInstance( 0 ), + m_pPIManager(0 ) +{ +} + +SalData::~SalData() +{ +} + +// This is our main entry point: +SalInstance *CreateSalInstance() +{ + LOGI("Android: CreateSalInstance!"); + AndroidSalInstance* pInstance = new AndroidSalInstance( std::make_unique() ); + new AndroidSalData( pInstance ); + pInstance->AcquireYieldMutex(); + return pInstance; +} + +void DestroySalInstance( SalInstance *pInst ) +{ + pInst->ReleaseYieldMutexAll(); + delete pInst; +} + +int AndroidSalSystem::ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) +{ + (void)rButtons; + LOGI("LibreOffice native dialog '%s': '%s'", + OUStringToOString(rTitle, RTL_TEXTENCODING_ASCII_US).getStr(), + OUStringToOString(rMessage, RTL_TEXTENCODING_ASCII_US).getStr()); + LOGI("Dialog '%s': '%s'", + OUStringToOString(rTitle, RTL_TEXTENCODING_ASCII_US).getStr(), + OUStringToOString(rMessage, RTL_TEXTENCODING_ASCII_US).getStr()); + + if (AndroidSalInstance::getInstance() != NULL) + { + // Does Android have a native dialog ? if not,. we have to do this ... + + // Of course it has. android.app.AlertDialog seems like a good + // choice, it even has one, two or three buttons. Naturally, + // it intended to be used from Java, so some verbose JNI + // horror would be needed to use it directly here. Probably we + // want some easier to use magic wrapper, hmm. + std::unique_ptr xBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Warning, VclButtonsType::Ok, + rMessage)); + xBox->set_title(rTitle); + xBox->run(); + } + else + LOGE("VCL not initialized"); + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/VisualBackendTest.cxx b/vcl/backendtest/VisualBackendTest.cxx new file mode 100644 index 000000000..08efc1d38 --- /dev/null +++ b/vcl/backendtest/VisualBackendTest.cxx @@ -0,0 +1,690 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +using namespace css; + +static void drawBitmapCentered(tools::Rectangle const& rRect, const Bitmap& aBitmap, + vcl::RenderContext& rRenderContext) +{ + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + + Size aBitmapSize(aBitmap.GetSizePixel()); + + Point aPoint(rRect.TopLeft()); + + aPoint.AdjustX((nWidth - aBitmapSize.Width()) / 2 ); + aPoint.AdjustY((nHeight - aBitmapSize.Height()) / 2 ); + + rRenderContext.DrawBitmap(aPoint, aBitmap); +} + +static void drawBitmapScaledAndCentered(tools::Rectangle const & rRect, Bitmap aBitmap, vcl::RenderContext& rRenderContext, BmpScaleFlag aFlag = BmpScaleFlag::Fast) +{ + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + + Size aBitmapSize(aBitmap.GetSizePixel()); + + double fWidthHeight = std::min(nWidth, nHeight); + double fScale = fWidthHeight / aBitmapSize.Width(); + aBitmap.Scale(fScale, fScale, aFlag); + + drawBitmapCentered(rRect, aBitmap, rRenderContext); +} + +static void drawBackgroundRect(tools::Rectangle const & rRect, Color aColor, vcl::RenderContext& rRenderContext) +{ + rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR); + rRenderContext.SetFillColor(aColor); + rRenderContext.SetLineColor(aColor); + rRenderContext.DrawRect(rRect); + rRenderContext.Pop(); +} + +static void assertAndSetBackground(vcl::test::TestResult eResult, tools::Rectangle const & rRect, vcl::RenderContext& rRenderContext) +{ + if (eResult == vcl::test::TestResult::Passed) + drawBackgroundRect(rRect, COL_GREEN, rRenderContext); + else if (eResult == vcl::test::TestResult::PassedWithQuirks) + drawBackgroundRect(rRect, COL_YELLOW, rRenderContext); + else if (eResult == vcl::test::TestResult::Failed) + drawBackgroundRect(rRect, COL_RED, rRenderContext); +} + +namespace { + +class VisualBackendTestWindow : public WorkWindow +{ +private: + Timer maUpdateTimer; + std::vector mTimePoints; + static constexpr unsigned char gnNumberOfTests = 9; + unsigned char mnTest; + bool mbAnimate; + ScopedVclPtr mpVDev; + +public: + VisualBackendTestWindow() + : WorkWindow(nullptr, WB_APP | WB_STDWORK) + , mnTest(10 * gnNumberOfTests) + , mbAnimate(mnTest % gnNumberOfTests == gnNumberOfTests - 1) + , mpVDev(VclPtr::Create()) + { + maUpdateTimer.SetInvokeHandler(LINK(this, VisualBackendTestWindow, updateHdl)); + maUpdateTimer.SetPriority(TaskPriority::DEFAULT_IDLE); + if (mbAnimate) + { + maUpdateTimer.SetTimeout(1000.0); + maUpdateTimer.Start(); + } + } + + virtual ~VisualBackendTestWindow() override + { + disposeOnce(); + } + + DECL_LINK(updateHdl, Timer*, void); + + virtual void KeyInput(const KeyEvent& rKEvt) override + { + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + if (nCode == KEY_BACKSPACE) + mnTest--; + else if(nCode == KEY_SPACE) + mnTest++; + + if (nCode == KEY_BACKSPACE || nCode == KEY_SPACE) + { + if (mnTest % gnNumberOfTests == gnNumberOfTests - 1) + { + mbAnimate = true; + maUpdateTimer.Start(); + } + else + { + mbAnimate = false; + Invalidate(); + } + } + } + + static std::vector setupRegions(int nPartitionsX, int nPartitionsY, int nWidth, int nHeight) + { + std::vector aRegions; + + for (int y = 0; y < nPartitionsY; y++) + { + for (int x = 0; x < nPartitionsX; x++) + { + long x1 = x * (nWidth / nPartitionsX); + long y1 = y * (nHeight / nPartitionsY); + long x2 = (x+1) * (nWidth / nPartitionsX); + long y2 = (y+1) * (nHeight / nPartitionsY); + + aRegions.emplace_back(x1 + 1, y1 + 1, x2 - 2, y2 - 2); + } + } + return aRegions; + } + + static void testRectangles(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(3, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPixel aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + static void testFilledRectangles(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(3, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(true); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(true); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(true); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + static void testDiamonds(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(3, 1, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + static void testLines(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(3, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkLines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkLines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkLines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupAALines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkAALines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupAALines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkAALines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupAALines(); + assertAndSetBackground(vcl::test::OutputDeviceTestCommon::checkAALines(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + static void testBitmaps(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(3, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmap(); + assertAndSetBackground(vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap(); + assertAndSetBackground(vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha(); + assertAndSetBackground(vcl::test::OutputDeviceTestBitmap::checkBitmapExWithAlpha(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawMask(); + assertAndSetBackground(vcl::test::OutputDeviceTestBitmap::checkMask(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + BitmapEx aBitmap = aOutDevTest.setupDrawBlend(); + assertAndSetBackground(vcl::test::OutputDeviceTestBitmap::checkBlend(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap.GetBitmap(), rRenderContext); + } + } + + static void testInvert(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(2, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_NONE(); + assertAndSetBackground(vcl::test::OutputDeviceTestRect::checkInvertRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_N50(); + assertAndSetBackground(vcl::test::OutputDeviceTestRect::checkInvertN50Rectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_TrackFrame(); + assertAndSetBackground(vcl::test::OutputDeviceTestRect::checkInvertTrackFrameRectangle(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupXOR(); + assertAndSetBackground(vcl::test::OutputDeviceTestAnotherOutDev::checkXOR(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + static void testClip(vcl::RenderContext& rRenderContext, int nWidth, int nHeight) + { + tools::Rectangle aRectangle; + size_t index = 0; + + std::vector aRegions = setupRegions(2, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipRectangle(); + assertAndSetBackground(vcl::test::OutputDeviceTestClip::checkClip(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolygon(); + assertAndSetBackground(vcl::test::OutputDeviceTestClip::checkClip(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolyPolygon(); + assertAndSetBackground(vcl::test::OutputDeviceTestClip::checkClip(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipB2DPolyPolygon(); + assertAndSetBackground(vcl::test::OutputDeviceTestClip::checkClip(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) override + { + if (mnTest % gnNumberOfTests == gnNumberOfTests - 1) + { + rRenderContext.SetBackground(Wallpaper(COL_GREEN)); + + static size_t nTimeIndex = 0; + static const size_t constSamplesFPS = 120; + double fps = 0.0; + + if (mTimePoints.size() < constSamplesFPS) + { + mTimePoints.push_back(std::chrono::high_resolution_clock::now()); + nTimeIndex++; + } + else + { + size_t current = nTimeIndex % constSamplesFPS; + mTimePoints[current] = std::chrono::high_resolution_clock::now(); + size_t last = (nTimeIndex + 1) % constSamplesFPS; + auto ms = std::chrono::duration_cast(mTimePoints[current] - mTimePoints[last]).count(); + fps = constSamplesFPS * 1000.0 / ms; + nTimeIndex++; + } + + double fTime = 0.5 + std::sin(nTimeIndex / 100.0) / 2.0; + + Size aSizePixel = GetSizePixel(); + + mpVDev->SetAntialiasing(AntialiasingFlags::EnableB2dDraw | AntialiasingFlags::PixelSnapHairline); + mpVDev->SetOutputSizePixel(aSizePixel); + mpVDev->SetBackground(Wallpaper(COL_LIGHTGRAY)); + mpVDev->Erase(); + mpVDev->SetFillColor(COL_LIGHTRED); + mpVDev->SetLineColor(COL_LIGHTBLUE); + + basegfx::B2DPolyPolygon polyPolygon; + + for (int b=10; b<14; b++) + { + basegfx::B2DPolygon polygon; + for (double a=0.0; a<360.0; a+=0.5) + { + double x = std::sin(basegfx::deg2rad(a)) * (b+1) * 20; + double y = std::cos(basegfx::deg2rad(a)) * (b+1) * 20; + polygon.append(basegfx::B2DPoint(x + 200 + 500 * fTime, y + 200 + 500 * fTime)); + } + polygon.setClosed(true); + polyPolygon.append(polygon); + } + + mpVDev->DrawPolyPolygon(polyPolygon); + + tools::Rectangle aGradientRect(Point(200, 200), Size(200 + fTime * 300, 200 + fTime * 300)); + mpVDev->DrawGradient(aGradientRect, Gradient(GradientStyle::Linear, COL_YELLOW, COL_BLUE)); + + rRenderContext.DrawOutDev(Point(), mpVDev->GetOutputSizePixel(), + Point(), mpVDev->GetOutputSizePixel(), + *mpVDev); + rRenderContext.SetTextColor(COL_LIGHTRED); + rRenderContext.DrawText(Point(10, 10), "FPS: " + OUString::number(int(fps))); + return; + } + + rRenderContext.SetBackground(Wallpaper(COL_GREEN)); + + Size aSize = GetOutputSizePixel(); + + long nWidth = aSize.Width(); + long nHeight = aSize.Height(); + + tools::Rectangle aRectangle; + size_t index = 0; + + if (mnTest % gnNumberOfTests == 0) + { + testRectangles(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 1) + { + testFilledRectangles(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 2) + { + testDiamonds(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 3) + { + testLines(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 4) + { + testBitmaps(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 5) + { + testInvert(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 6) + { + testClip(rRenderContext, nWidth, nHeight); + } + else if (mnTest % gnNumberOfTests == 7) + { + std::vector aRegions = setupRegions(2, 2, nWidth, nHeight); + + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawOutDev(); + assertAndSetBackground(vcl::test::OutputDeviceTestAnotherOutDev::checkDrawOutDev(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDashedLine(); + assertAndSetBackground(vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap), aRectangle, rRenderContext); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestGradient aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupLinearGradient(); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + aRectangle = aRegions[index++]; + { + vcl::test::OutputDeviceTestGradient aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRadialGradient(); + drawBitmapScaledAndCentered(aRectangle, aBitmap, rRenderContext); + } + } + } +}; + +} + +IMPL_LINK_NOARG(VisualBackendTestWindow, updateHdl, Timer *, void) +{ + if (mbAnimate) + { + maUpdateTimer.SetTimeout(1.0); + maUpdateTimer.Start(); + Invalidate(); + } +} + +namespace { + +class VisualBackendTestApp : public Application +{ + +public: + VisualBackendTestApp() + {} + + virtual int Main() override + { + try + { + ScopedVclPtrInstance aMainWindow; + + aMainWindow->SetText("VCL Test"); + aMainWindow->Show(); + + Application::Execute(); + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("vcl.app", "Fatal"); + return 1; + } + catch (const std::exception& rException) + { + SAL_WARN("vcl.app", "Fatal exception: " << rException.what()); + return 1; + } + return 0; + } + +protected: + void Init() override + { + try + { + uno::Reference xComponentContext = ::cppu::defaultBootstrap_InitialComponentContext(); + uno::Reference xMSF(xComponentContext->getServiceManager(), uno::UNO_QUERY); + + if (!xMSF.is()) + Application::Abort("Bootstrap failure - no service manager"); + + comphelper::setProcessServiceFactory(xMSF); + } + catch (const uno::Exception &e) + { + Application::Abort("Bootstrap exception " + e.Message); + } + } + + void DeInit() override + { + uno::Reference xComponent(comphelper::getProcessComponentContext(), uno::UNO_QUERY_THROW); + xComponent->dispose(); + comphelper::setProcessServiceFactory(nullptr); + } +}; + +} + +void vclmain::createApplication() +{ + static VisualBackendTestApp aApplication; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/bitmap.cxx b/vcl/backendtest/outputdevice/bitmap.cxx new file mode 100644 index 000000000..79cd3d379 --- /dev/null +++ b/vcl/backendtest/outputdevice/bitmap.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include + +namespace vcl::test { + +Bitmap OutputDeviceTestBitmap::setupDrawTransformedBitmap() +{ + Size aBitmapSize(9, 9); + Bitmap aBitmap(aBitmapSize, 24); + { + BitmapScopedWriteAccess aWriteAccess(aBitmap); + aWriteAccess->Erase(constFillColor); + aWriteAccess->SetLineColor(COL_YELLOW); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(2, 2, 6, 6)); + } + + initialSetup(13, 13, constBackgroundColor); + + basegfx::B2DHomMatrix aTransform; + aTransform.scale(aBitmapSize.Width(), aBitmapSize.Height()); + aTransform.translate((maVDRectangle.GetWidth() / 2.0) - (aBitmapSize.Width() / 2.0), + (maVDRectangle.GetHeight() / 2.0) - (aBitmapSize.Height() / 2.0)); + + mpVirtualDevice->DrawTransformedBitmapEx(aTransform, BitmapEx(aBitmap)); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + + +Bitmap OutputDeviceTestBitmap::setupDrawBitmap() +{ + Size aBitmapSize(9, 9); + Bitmap aBitmap(aBitmapSize, 24); + { + BitmapScopedWriteAccess aWriteAccess(aBitmap); + aWriteAccess->Erase(constFillColor); + aWriteAccess->SetLineColor(COL_YELLOW); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(2, 2, 6, 6)); + } + + initialSetup(13, 13, constBackgroundColor); + + Point aPoint((maVDRectangle.GetWidth() / 2.0) - (aBitmapSize.Width() / 2.0), + (maVDRectangle.GetHeight() / 2.0) - (aBitmapSize.Height() / 2.0)); + + mpVirtualDevice->DrawBitmapEx(aPoint, BitmapEx(aBitmap)); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestBitmap::setupDrawBitmapExWithAlpha() +{ + Size aBitmapSize(9, 9); + Bitmap aBitmap(aBitmapSize, 24); + { + BitmapScopedWriteAccess aWriteAccess(aBitmap); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(Color(0xFF, 0xFF, 0x00)); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5)); + } + + AlphaMask aAlpha(aBitmapSize); + { + AlphaScopedWriteAccess aWriteAccess(aAlpha); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(Color(0x44, 0x44, 0x44)); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5)); + } + + initialSetup(13, 13, constBackgroundColor); + + Point aPoint(alignToCenter(maVDRectangle, tools::Rectangle(Point(), aBitmapSize)).TopLeft()); + + mpVirtualDevice->DrawBitmapEx(aPoint, BitmapEx(aBitmap, aAlpha)); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestBitmap::setupDrawMask() +{ + Size aBitmapSize(9, 9); + Bitmap aBitmap(aBitmapSize, 24); + { + BitmapScopedWriteAccess aWriteAccess(aBitmap); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5)); + } + + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->DrawMask(Point(2, 2), aBitmap, constLineColor); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +BitmapEx OutputDeviceTestBitmap::setupDrawBlend() +{ + Size aBitmapSize(9, 9); + Bitmap aBitmap(aBitmapSize, 24); + { + BitmapScopedWriteAccess aWriteAccess(aBitmap); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(Color(0xFF, 0xFF, 0x00)); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5)); + } + + AlphaMask aAlpha(aBitmapSize); + { + AlphaScopedWriteAccess aWriteAccess(aAlpha); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(Color(0x44, 0x44, 0x44)); + aWriteAccess->DrawRect(tools::Rectangle(0, 0, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5)); + } + + initialSetup(13, 13, COL_TRANSPARENT, false, true); + mpVirtualDevice->SetFillColor(constBackgroundColor); + mpVirtualDevice->SetLineColor(constBackgroundColor); + // Leave the outer part of the device transparent, the inner part set to the background color. + // This will test blending of VirtualDevice's "alpha" device (outer yellow rectangle + // will be blended with transparent background, inner with the grey one). + mpVirtualDevice->DrawRect( tools::Rectangle( Point( 3, 3 ), Size( 7, 7 ))); + + Point aPoint(alignToCenter(maVDRectangle, tools::Rectangle(Point(), aBitmapSize)).TopLeft()); + + mpVirtualDevice->DrawBitmapEx(aPoint, BitmapEx(aBitmap, aAlpha)); + + return mpVirtualDevice->GetBitmapEx(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +TestResult OutputDeviceTestBitmap::checkTransformedBitmap(Bitmap& rBitmap) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, + COL_YELLOW, constFillColor, COL_YELLOW, constFillColor, constFillColor + }; + return checkRectangles(rBitmap, aExpected); +} + +TestResult OutputDeviceTestBitmap::checkBitmapExWithAlpha(Bitmap& rBitmap) +{ + const Color aBlendedColor(0xEE, 0xEE, 0x33); + + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, + aBlendedColor, constBackgroundColor, constBackgroundColor, + aBlendedColor, constBackgroundColor + }; + return checkRectangles(rBitmap, aExpected); +} + +TestResult OutputDeviceTestBitmap::checkMask(Bitmap& rBitmap) +{ + return checkRectangle(rBitmap); +} + +TestResult OutputDeviceTestBitmap::checkBlend(BitmapEx& rBitmapEx) +{ + const Color aBlendedColor(0xEE, 0xEE, 0x33); + + std::vector aExpected + { + COL_WHITE, COL_WHITE, COL_YELLOW, constBackgroundColor, + constBackgroundColor, aBlendedColor, constBackgroundColor + }; + Bitmap aBitmap(rBitmapEx.GetBitmap()); + return checkRectangles(aBitmap, aExpected); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/clip.cxx b/vcl/backendtest/outputdevice/clip.cxx new file mode 100644 index 000000000..86064b583 --- /dev/null +++ b/vcl/backendtest/outputdevice/clip.cxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test +{ +Bitmap OutputDeviceTestClip::setupClipRectangle() +{ + initialSetup(13, 13, constBackgroundColor); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(2); + mpVirtualDevice->SetClipRegion(vcl::Region(rectangle)); + mpVirtualDevice->SetBackground(constFillColor); + mpVirtualDevice->Erase(maVDRectangle); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestClip::setupClipPolygon() +{ + initialSetup(13, 13, constBackgroundColor); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(2); + mpVirtualDevice->SetClipRegion(vcl::Region(tools::Polygon(rectangle))); + mpVirtualDevice->SetBackground(constFillColor); + mpVirtualDevice->Erase(maVDRectangle); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestClip::setupClipPolyPolygon() +{ + initialSetup(13, 13, constBackgroundColor); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(2); + mpVirtualDevice->SetClipRegion(vcl::Region(tools::PolyPolygon(rectangle))); + mpVirtualDevice->SetBackground(constFillColor); + mpVirtualDevice->Erase(maVDRectangle); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestClip::setupClipB2DPolyPolygon() +{ + initialSetup(13, 13, constBackgroundColor); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(2); + mpVirtualDevice->SetClipRegion(vcl::Region(basegfx::B2DPolyPolygon(basegfx::B2DPolygon{ + basegfx::B2DPoint(rectangle.getX(), rectangle.getY()), + basegfx::B2DPoint(rectangle.getX(), rectangle.getY() + rectangle.getHeight()), + basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(), + rectangle.getY() + rectangle.getHeight()), + basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(), rectangle.getY()), + }))); + mpVirtualDevice->SetBackground(constFillColor); + mpVirtualDevice->Erase(maVDRectangle); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +TestResult OutputDeviceTestClip::checkClip(Bitmap& aBitmap) +{ + std::vector aExpected{ constBackgroundColor, constBackgroundColor, constFillColor, + constFillColor, constFillColor, constFillColor, + constFillColor }; + return checkRectangles(aBitmap, aExpected); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/common.cxx b/vcl/backendtest/outputdevice/common.cxx new file mode 100644 index 000000000..a5d032315 --- /dev/null +++ b/vcl/backendtest/outputdevice/common.cxx @@ -0,0 +1,478 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include + +namespace vcl::test { + +namespace +{ + +int deltaColor(BitmapColor aColor1, BitmapColor aColor2) +{ + int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed()); + int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen()); + int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue()); + + return std::max(std::max(deltaR, deltaG), deltaB); +} + +void checkValue(BitmapScopedWriteAccess& pAccess, int x, int y, Color aExpected, + int& nNumberOfQuirks, int& nNumberOfErrors, bool bQuirkMode, int nColorDeltaThresh = 0) +{ + const bool bColorize = false; + Color aColor = pAccess->GetPixel(y, x); + int nColorDelta = deltaColor(aColor, aExpected); + + if (nColorDelta <= nColorDeltaThresh) + { + if (bColorize) + pAccess->SetPixel(y, x, COL_LIGHTGREEN); + } + else if (bQuirkMode) + { + nNumberOfQuirks++; + if (bColorize) + pAccess->SetPixel(y, x, COL_YELLOW); + } + else + { + nNumberOfErrors++; + if (bColorize) + pAccess->SetPixel(y, x, COL_LIGHTRED); + } +} + +TestResult checkRect(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + long nHeight = pAccess->Height(); + long nWidth = pAccess->Width(); + + long firstX = 0 + aLayerNumber; + long firstY = 0 + aLayerNumber; + + long lastX = nWidth - aLayerNumber - 1; + long lastY = nHeight - aLayerNumber - 1; + + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + // check corner quirks + checkValue(pAccess, firstX, firstY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, lastX, firstY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, firstX, lastY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, lastX, lastY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + + for (long y = firstY + 1; y <= lastY - 1; y++) + { + checkValue(pAccess, firstX, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(pAccess, lastX, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + } + for (long x = firstX + 1; x <= lastX - 1; x++) + { + checkValue(pAccess, x, firstY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(pAccess, x, lastY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + } + if (nNumberOfQuirks > 0) + aResult = TestResult::PassedWithQuirks; + if (nNumberOfErrors > 0) + aResult = TestResult::Failed; + return aResult; +} + +TestResult checkHorizontalVerticalDiagonalLines(Bitmap& rBitmap, Color aExpectedColor, int nColorThresh) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + long nWidth = pAccess->Width(); + long nHeight = pAccess->Height(); + + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + // check horizontal line + { + long startX = 4; + long endX = nWidth - 2; + + long y = 1; + + checkValue(pAccess, startX, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + checkValue(pAccess, endX, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + + for (long x = startX + 1; x <= endX - 1; x++) + { + checkValue(pAccess, x, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false, nColorThresh); + } + } + + // check vertical line + { + long startY = 4; + long endY = nHeight - 2; + + long x = 1; + + checkValue(pAccess, x, startY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + checkValue(pAccess, x, endY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + + for (long y = startY + 1; y <= endY - 1; y++) + { + checkValue(pAccess, x, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false, nColorThresh); + } + } + + // check diagonal line + { + long startX = 1; + long endX = nWidth - 2; + + long startY = 1; + long endY = nHeight - 2; + + long x = startX; + long y = startY; + + checkValue(pAccess, startX, startY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + checkValue(pAccess, endX, endY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true, nColorThresh); + + x++; y++; + + while(y <= endY - 1 && x <= endX - 1) + { + checkValue(pAccess, x, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false, nColorThresh); + x++; y++; + } + } + + if (nNumberOfQuirks > 0) + aResult = TestResult::PassedWithQuirks; + if (nNumberOfErrors > 0) + aResult = TestResult::Failed; + return aResult; +} + +TestResult checkDiamondLine(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + long nHeight = pAccess->Height(); + long nWidth = pAccess->Width(); + + long midX = nWidth / 2; + long midY = nHeight / 2; + + long firstX = aLayerNumber; + long lastX = nWidth - aLayerNumber - 1; + + long firstY = aLayerNumber; + long lastY = nHeight - aLayerNumber - 1; + + long offsetFromMid = 0; + + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + checkValue(pAccess, firstX, midY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, lastX, midY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, midX, firstY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + checkValue(pAccess, midX, lastY, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, true); + + offsetFromMid = 1; + for (long x = firstX + 1; x <= midX - 1; x++) + { + checkValue(pAccess, x, midY - offsetFromMid, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(pAccess, x, midY + offsetFromMid, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + + offsetFromMid++; + } + + offsetFromMid = midY - aLayerNumber - 1; + + for (long x = midX + 1; x <= lastX - 1; x++) + { + checkValue(pAccess, x, midY - offsetFromMid, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + checkValue(pAccess, x, midY + offsetFromMid, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + + offsetFromMid--; + } + + if (nNumberOfQuirks > 0) + aResult = TestResult::PassedWithQuirks; + if (nNumberOfErrors > 0) + aResult = TestResult::Failed; + return aResult; +} + +} // end anonymous namespace + +const Color OutputDeviceTestCommon::constBackgroundColor(COL_LIGHTGRAY); +const Color OutputDeviceTestCommon::constLineColor(COL_LIGHTBLUE); +const Color OutputDeviceTestCommon::constFillColor(COL_BLUE); + +OutputDeviceTestCommon::OutputDeviceTestCommon() +{} + +OUString OutputDeviceTestCommon::getRenderBackendName() const +{ + if (mpVirtualDevice && mpVirtualDevice->GetGraphics()) + { + SalGraphics const * pGraphics = mpVirtualDevice->GetGraphics(); + return pGraphics->getRenderBackendName(); + } + return OUString(); +} + +void OutputDeviceTestCommon::initialSetup(long nWidth, long nHeight, Color aColor, bool bEnableAA, bool bAlphaVirtualDevice) +{ + if (bAlphaVirtualDevice) + mpVirtualDevice = VclPtr::Create(DeviceFormat::DEFAULT, DeviceFormat::DEFAULT); + else + mpVirtualDevice = VclPtr::Create(DeviceFormat::DEFAULT); + + maVDRectangle = tools::Rectangle(Point(), Size (nWidth, nHeight)); + mpVirtualDevice->SetOutputSizePixel(maVDRectangle.GetSize()); + if (bEnableAA) + mpVirtualDevice->SetAntialiasing(AntialiasingFlags::EnableB2dDraw | AntialiasingFlags::PixelSnapHairline); + else + mpVirtualDevice->SetAntialiasing(AntialiasingFlags::NONE); + mpVirtualDevice->SetBackground(Wallpaper(aColor)); + mpVirtualDevice->Erase(); +} + +TestResult OutputDeviceTestCommon::checkLines(Bitmap& rBitmap) +{ + return checkHorizontalVerticalDiagonalLines(rBitmap, constLineColor, 0); +} + +TestResult OutputDeviceTestCommon::checkAALines(Bitmap& rBitmap) +{ + return checkHorizontalVerticalDiagonalLines(rBitmap, constLineColor, 30); // 30 color values threshold delta +} + +static void checkResult(TestResult eResult, TestResult & eTotal) +{ + if (eTotal == TestResult::Failed) + return; + + if (eResult == TestResult::Failed) + eTotal = TestResult::Failed; + + if (eResult == TestResult::PassedWithQuirks) + eTotal = TestResult::PassedWithQuirks; +} + +TestResult OutputDeviceTestCommon::checkInvertRectangle(Bitmap& aBitmap) +{ + TestResult aReturnValue = TestResult::Passed; + TestResult eResult; + + std::vector aExpected{ COL_WHITE, COL_WHITE }; + eResult = checkRectangles(aBitmap, aExpected); + checkResult(eResult, aReturnValue); + + eResult = checkFilled(aBitmap, tools::Rectangle(Point(2, 2), Size(8, 8)), COL_LIGHTCYAN); + checkResult(eResult, aReturnValue); + + eResult = checkFilled(aBitmap, tools::Rectangle(Point(10, 2), Size(8, 8)), COL_LIGHTMAGENTA); + checkResult(eResult, aReturnValue); + + eResult = checkFilled(aBitmap, tools::Rectangle(Point(2, 10), Size(8, 8)), COL_YELLOW); + checkResult(eResult, aReturnValue); + + eResult = checkFilled(aBitmap, tools::Rectangle(Point(10, 10), Size(8, 8)), COL_BLACK); + checkResult(eResult, aReturnValue); + + return aReturnValue; +} + +TestResult OutputDeviceTestCommon::checkChecker(Bitmap& rBitmap, sal_Int32 nStartX, sal_Int32 nEndX, sal_Int32 nStartY, sal_Int32 nEndY, std::vector const & rExpected) +{ + TestResult aReturnValue = TestResult::Passed; + + int choice = 0; + for (sal_Int32 y = nStartY; y <= nEndY; ++y) + { + for (sal_Int32 x = nStartX; x <= nEndX; ++x) + { + TestResult eResult = checkFilled(rBitmap, tools::Rectangle(Point(x, y), Size(1, 1)), rExpected[choice % 2]); + checkResult(eResult, aReturnValue); + choice++; + } + choice++; + } + return aReturnValue; +} + +TestResult OutputDeviceTestCommon::checkInvertN50Rectangle(Bitmap& aBitmap) +{ + TestResult aReturnValue = TestResult::Passed; + TestResult eResult; + + std::vector aExpected{ COL_WHITE, COL_WHITE }; + eResult = checkRectangles(aBitmap, aExpected); + checkResult(eResult, aReturnValue); + + eResult = checkChecker(aBitmap, 2, 9, 2, 9, { COL_LIGHTCYAN, COL_LIGHTRED }); + checkResult(eResult, aReturnValue); + eResult = checkChecker(aBitmap, 2, 9, 10, 17, { COL_YELLOW, COL_LIGHTBLUE }); + checkResult(eResult, aReturnValue); + eResult = checkChecker(aBitmap, 10, 17, 2, 9, { COL_LIGHTMAGENTA, COL_LIGHTGREEN }); + checkResult(eResult, aReturnValue); + eResult = checkChecker(aBitmap, 10, 17, 10, 17, { COL_BLACK, COL_WHITE }); + checkResult(eResult, aReturnValue); + + return aReturnValue; +} + +TestResult OutputDeviceTestCommon::checkInvertTrackFrameRectangle(Bitmap& aBitmap) +{ + std::vector aExpected + { + COL_WHITE, COL_WHITE + }; + return checkRectangles(aBitmap, aExpected); +} + +TestResult OutputDeviceTestCommon::checkRectangle(Bitmap& aBitmap) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, constLineColor, + constBackgroundColor, constBackgroundColor, constLineColor, constBackgroundColor + }; + return checkRectangles(aBitmap, aExpected); +} + +TestResult OutputDeviceTestCommon::checkRectangleAA(Bitmap& aBitmap) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, constLineColor, + constBackgroundColor, constBackgroundColor, constLineColor, constBackgroundColor + }; + return checkRectangles(aBitmap, aExpected); +} + +TestResult OutputDeviceTestCommon::checkFilledRectangle(Bitmap& aBitmap, bool useLineColor) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, + useLineColor ? constLineColor : constFillColor, + constFillColor, constFillColor, constFillColor, constFillColor + }; + return checkRectangles(aBitmap, aExpected); +} + +TestResult OutputDeviceTestCommon::checkFilled(Bitmap& rBitmap, tools::Rectangle aRectangle, Color aExpectedColor) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + + TestResult aResult = TestResult::Passed; + int nNumberOfQuirks = 0; + int nNumberOfErrors = 0; + + for (long y = aRectangle.Top(); y < aRectangle.Top() + aRectangle.GetHeight(); y++) + { + for (long x = aRectangle.Left(); x < aRectangle.Left() + aRectangle.GetWidth(); x++) + { + checkValue(pAccess, x, y, aExpectedColor, nNumberOfQuirks, nNumberOfErrors, false); + } + } + + if (nNumberOfQuirks > 0) + aResult = TestResult::PassedWithQuirks; + + if (nNumberOfErrors > 0) + aResult = TestResult::Failed; + + return aResult; +} + +TestResult OutputDeviceTestCommon::checkRectangles(Bitmap& aBitmap, std::vector& aExpectedColors) +{ + TestResult aReturnValue = TestResult::Passed; + for (size_t i = 0; i < aExpectedColors.size(); i++) + { + TestResult eResult = checkRect(aBitmap, i, aExpectedColors[i]); + + if (eResult == TestResult::Failed) + aReturnValue = TestResult::Failed; + if (eResult == TestResult::PassedWithQuirks && aReturnValue != TestResult::Failed) + aReturnValue = TestResult::PassedWithQuirks; + } + return aReturnValue; +} + +TestResult OutputDeviceTestCommon::checkRectangle(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor) +{ + return checkRect(rBitmap, aLayerNumber, aExpectedColor); +} + +tools::Rectangle OutputDeviceTestCommon::alignToCenter(tools::Rectangle aRect1, tools::Rectangle aRect2) +{ + Point aPoint((aRect1.GetWidth() / 2.0) - (aRect2.GetWidth() / 2.0), + (aRect1.GetHeight() / 2.0) - (aRect2.GetHeight() / 2.0)); + + return tools::Rectangle(aPoint, aRect2.GetSize()); +} + +TestResult OutputDeviceTestCommon::checkDiamond(Bitmap& rBitmap) +{ + return checkDiamondLine(rBitmap, 1, constLineColor); +} + +void OutputDeviceTestCommon::createDiamondPoints(tools::Rectangle rRect, int nOffset, + Point& rPoint1, Point& rPoint2, + Point& rPoint3, Point& rPoint4) +{ + long midPointX = rRect.Left() + (rRect.Right() - rRect.Left()) / 2.0; + long midPointY = rRect.Top() + (rRect.Bottom() - rRect.Top()) / 2.0; + + rPoint1 = Point(midPointX , midPointY - nOffset); + rPoint2 = Point(midPointX + nOffset, midPointY ); + rPoint3 = Point(midPointX , midPointY + nOffset); + rPoint4 = Point(midPointX - nOffset, midPointY ); +} + +void OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints(tools::Rectangle rRect, + Point& rHorizontalLinePoint1, Point& rHorizontalLinePoint2, + Point& rVerticalLinePoint1, Point& rVerticalLinePoint2, + Point& rDiagonalLinePoint1, Point& rDiagonalLinePoint2) +{ + rHorizontalLinePoint1 = Point(4, 1); + rHorizontalLinePoint2 = Point(rRect.Right() - 1, 1); + + rVerticalLinePoint1 = Point(1, 4); + rVerticalLinePoint2 = Point(1,rRect.Bottom() - 1); + + rDiagonalLinePoint1 = Point(1, 1); + rDiagonalLinePoint2 = Point(rRect.Right() - 1, rRect.Bottom() - 1); +} + +TestResult OutputDeviceTestCommon::checkBezier(Bitmap& rBitmap) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor + }; + // Check the bezier doesn't go over to the margins first + // TODO extend the check with more exact assert + return checkRectangles(rBitmap, aExpected); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/gradient.cxx b/vcl/backendtest/outputdevice/gradient.cxx new file mode 100644 index 000000000..9880fedd1 --- /dev/null +++ b/vcl/backendtest/outputdevice/gradient.cxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include + +namespace vcl::test { + +Bitmap OutputDeviceTestGradient::setupLinearGradient() +{ + initialSetup(12, 12, constBackgroundColor); + + Gradient aGradient(GradientStyle::Linear, Color(0xFF, 0xFF, 0xFF), Color(0x00, 0x00, 0x00)); + aGradient.SetAngle(900); + tools::Rectangle aDrawRect(maVDRectangle.Left() + 1, maVDRectangle.Top() + 1, + maVDRectangle.Right() - 1, maVDRectangle.Bottom() - 1); + mpVirtualDevice->DrawGradient(aDrawRect, aGradient); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestGradient::setupRadialGradient() +{ + initialSetup(12, 12, constBackgroundColor); + + Gradient aGradient(GradientStyle::Radial, Color(0xFF, 0xFF, 0xFF), Color(0x00, 0x00, 0x00)); + tools::Rectangle aDrawRect(maVDRectangle.Left() + 1, maVDRectangle.Top() + 1, + maVDRectangle.Right() - 1, maVDRectangle.Bottom() - 1); + mpVirtualDevice->DrawGradient(aDrawRect, aGradient); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/line.cxx b/vcl/backendtest/outputdevice/line.cxx new file mode 100644 index 000000000..5b5d73261 --- /dev/null +++ b/vcl/backendtest/outputdevice/line.cxx @@ -0,0 +1,200 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +#include +#include + +#include + +namespace vcl::test { + +namespace +{ + +void drawLineOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset) +{ + Point aLeftTop (rRect.Left() + nOffset, rRect.Top() + nOffset); + Point aRightTop (rRect.Right() - nOffset, rRect.Top() + nOffset); + Point aLeftBottom (rRect.Left() + nOffset, rRect.Bottom() - nOffset); + Point aRightBottom (rRect.Right() - nOffset, rRect.Bottom() - nOffset); + + rDevice.DrawLine(aLeftTop, aRightTop); + rDevice.DrawLine(aRightTop, aRightBottom); + rDevice.DrawLine(aRightBottom, aLeftBottom); + rDevice.DrawLine(aLeftBottom, aLeftTop); +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestLine::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawLineOffset(*mpVirtualDevice, maVDRectangle, 2); + drawLineOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestLine::setupDiamond() +{ + initialSetup(11, 11, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aPoint1, aPoint2, aPoint3, aPoint4; + OutputDeviceTestCommon::createDiamondPoints(maVDRectangle, 4, aPoint1, aPoint2, aPoint3, aPoint4); + + mpVirtualDevice->DrawLine(aPoint1, aPoint2); + mpVirtualDevice->DrawLine(aPoint2, aPoint3); + mpVirtualDevice->DrawLine(aPoint3, aPoint4); + mpVirtualDevice->DrawLine(aPoint4, aPoint1); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestLine::setupLines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + mpVirtualDevice->DrawLine(aHorizontalLinePoint1, aHorizontalLinePoint2); + mpVirtualDevice->DrawLine(aVerticalLinePoint1, aVerticalLinePoint2); + mpVirtualDevice->DrawLine(aDiagonalLinePoint1, aDiagonalLinePoint2); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestLine::setupAALines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetAntialiasing(AntialiasingFlags::EnableB2dDraw); + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + mpVirtualDevice->DrawLine(aHorizontalLinePoint1, aHorizontalLinePoint2); + mpVirtualDevice->DrawLine(aVerticalLinePoint1, aVerticalLinePoint2); + mpVirtualDevice->DrawLine(aDiagonalLinePoint1, aDiagonalLinePoint2); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestLine::setupDashedLine() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + tools::Rectangle rectangle = maVDRectangle; + rectangle.shrink(2); + + std::vector stroke({ 2.0, 1.0 }); + mpVirtualDevice->DrawPolyLineDirect( basegfx::B2DHomMatrix(), + basegfx::B2DPolygon{ + basegfx::B2DPoint(rectangle.getX(), rectangle.getY()), + basegfx::B2DPoint(rectangle.getX(), rectangle.getY() + rectangle.getHeight()), + basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(), + rectangle.getY() + rectangle.getHeight()), + basegfx::B2DPoint(rectangle.getX() + rectangle.getWidth(), rectangle.getY()), + basegfx::B2DPoint(rectangle.getX(), rectangle.getY())}, + 1, 0, &stroke, basegfx::B2DLineJoin::NONE, css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0), true ); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +TestResult OutputDeviceTestLine::checkDashedLine(Bitmap& rBitmap) +{ + TestResult returnValue = TestResult::Passed; + for (int i = 0; i < 7; i++) + { + TestResult eResult = TestResult::Passed; + if( i == 2 ) + { + // Build a sequence of pixels for the drawn rectangle border, + // check that they alternate appropriately (there should be + // normally 2 line, 1 background). + std::list< bool > dash; // true - line color, false - background + const int width = rBitmap.GetSizePixel().Width(); + const int height = rBitmap.GetSizePixel().Height(); + BitmapReadAccess access(rBitmap); + for( int x = 2; x < width - 2; ++x ) + dash.push_back( access.GetPixel( 2, x ) == constLineColor ); + for( int y = 3; y < height - 3; ++y ) + dash.push_back( access.GetPixel( y, width - 3 ) == constLineColor ); + for( int x = width - 3; x >= 2; --x ) + dash.push_back( access.GetPixel( height - 3, x ) == constLineColor ); + for( int y = height - 4; y >= 3; --y ) + dash.push_back( access.GetPixel( y, 2 ) == constLineColor ); + for( int x = 2; x < width - 2; ++x ) // repeat, to check also the corner + dash.push_back( access.GetPixel( 2, x ) == constLineColor ); + bool last = false; + int lastCount = 0; + while( !dash.empty()) + { + if( dash.front() == last ) + { + ++lastCount; + if( lastCount > ( last ? 4 : 3 )) + eResult = TestResult::Failed; + else if( lastCount > ( last ? 3 : 2 ) && eResult != TestResult::Failed) + eResult = TestResult::PassedWithQuirks; + } + else + { + last = dash.front(); + lastCount = 1; + } + dash.pop_front(); + } + } + else + { + eResult = OutputDeviceTestCommon::checkRectangle(rBitmap, i, constBackgroundColor); + } + + if (eResult == TestResult::Failed) + returnValue = TestResult::Failed; + if (eResult == TestResult::PassedWithQuirks && returnValue != TestResult::Failed) + returnValue = TestResult::PassedWithQuirks; + } + return returnValue; +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/outputdevice.cxx b/vcl/backendtest/outputdevice/outputdevice.cxx new file mode 100644 index 000000000..07d66ffb4 --- /dev/null +++ b/vcl/backendtest/outputdevice/outputdevice.cxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test { + +Bitmap OutputDeviceTestAnotherOutDev::setupDrawOutDev() +{ + ScopedVclPtrInstance pSourceDev; + Size aSourceSize(9, 9); + pSourceDev->SetOutputSizePixel(aSourceSize); + pSourceDev->SetBackground(Wallpaper(constFillColor)); + pSourceDev->Erase(); + + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->DrawOutDev(Point(2, 2), aSourceSize, Point(), aSourceSize, *pSourceDev); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestAnotherOutDev::setupXOR() +{ + initialSetup(13, 13, constBackgroundColor); + + tools::Rectangle aDrawRectangle(maVDRectangle); + aDrawRectangle.shrink(2); + + tools::Rectangle aScissorRectangle(maVDRectangle); + aScissorRectangle.shrink(4); + + mpVirtualDevice->SetRasterOp(RasterOp::Xor); + mpVirtualDevice->SetFillColor(constFillColor); + mpVirtualDevice->DrawRect(aDrawRectangle); + + mpVirtualDevice->SetRasterOp(RasterOp::N0); + mpVirtualDevice->SetFillColor(COL_BLACK); + mpVirtualDevice->DrawRect(aScissorRectangle); + + mpVirtualDevice->SetRasterOp(RasterOp::Xor); + mpVirtualDevice->SetFillColor(constFillColor); + mpVirtualDevice->DrawRect(aDrawRectangle); + + mpVirtualDevice->SetRasterOp(RasterOp::Xor); + mpVirtualDevice->SetLineColor(constFillColor); + mpVirtualDevice->SetFillColor(); + // Rectangle drawn twice is a no-op. + aDrawRectangle = maVDRectangle; + mpVirtualDevice->DrawRect(aDrawRectangle); + mpVirtualDevice->DrawRect(aDrawRectangle); + // Rectangle drawn three times is like drawing once. + aDrawRectangle.shrink(1); + mpVirtualDevice->DrawRect(aDrawRectangle); + mpVirtualDevice->DrawRect(aDrawRectangle); + mpVirtualDevice->DrawRect(aDrawRectangle); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +TestResult OutputDeviceTestAnotherOutDev::checkDrawOutDev(Bitmap& rBitmap) +{ + std::vector aExpected + { + constBackgroundColor, constBackgroundColor, + constFillColor, constFillColor, constFillColor, constFillColor, constFillColor + }; + return checkRectangles(rBitmap, aExpected); +} + +TestResult OutputDeviceTestAnotherOutDev::checkXOR(Bitmap& rBitmap) +{ + Color xorColor( constBackgroundColor.GetRed() ^ constFillColor.GetRed(), + constBackgroundColor.GetGreen() ^ constFillColor.GetGreen(), + constBackgroundColor.GetBlue() ^ constFillColor.GetBlue()); + std::vector aExpected + { + constBackgroundColor, xorColor, + constBackgroundColor, constBackgroundColor, + constFillColor, constFillColor, + constFillColor + }; + return checkRectangles(rBitmap, aExpected); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/pixel.cxx b/vcl/backendtest/outputdevice/pixel.cxx new file mode 100644 index 000000000..71997868f --- /dev/null +++ b/vcl/backendtest/outputdevice/pixel.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test { + +namespace +{ + +void drawPixelOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset) +{ + for (long x = 0 + nOffset; x < (rRect.GetWidth() - nOffset); ++x) + { + long y1 = nOffset; + long y2 = rRect.GetHeight() - nOffset - 1; + + rDevice.DrawPixel(Point(x, y1)); + rDevice.DrawPixel(Point(x, y2)); + } + + for (long y = 0 + nOffset; y < (rRect.GetHeight() - nOffset); ++y) + { + long x1 = nOffset; + long x2 = rRect.GetWidth() - nOffset - 1; + + rDevice.DrawPixel(Point(x1, y)); + rDevice.DrawPixel(Point(x2, y)); + } +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPixel::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawPixelOffset(*mpVirtualDevice, maVDRectangle, 2); + drawPixelOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/polygon.cxx b/vcl/backendtest/outputdevice/polygon.cxx new file mode 100644 index 000000000..8d207ade9 --- /dev/null +++ b/vcl/backendtest/outputdevice/polygon.cxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test { + +namespace +{ + +void drawPolygonOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset, int nFix = 0) +{ + // Note: According to https://lists.freedesktop.org/archives/libreoffice/2019-November/083709.html + // filling polygons always skips the right-most and bottom-most pixels, in order to avoid + // overlaps when drawing adjacent polygons. Specifying nFix = 1 allows to visually compensate + // for this by making the polygon explicitly larger. + tools::Polygon aPolygon(4); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Top() + nOffset), 0); + aPolygon.SetPoint(Point(rRect.Right() - nOffset + nFix, rRect.Top() + nOffset), 1); + aPolygon.SetPoint(Point(rRect.Right() - nOffset + nFix, rRect.Bottom() - nOffset + nFix), 2); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Bottom() - nOffset + nFix), 3); + aPolygon.Optimize(PolyOptimizeFlags::CLOSE); + + rDevice.DrawPolygon(aPolygon); +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPolygon::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawPolygonOffset(*mpVirtualDevice, maVDRectangle, 2); + drawPolygonOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolygon::setupFilledRectangle(bool useLineColor) +{ + initialSetup(13, 13, constBackgroundColor); + + if(useLineColor) + mpVirtualDevice->SetLineColor(constLineColor); + else + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(constFillColor); + drawPolygonOffset(*mpVirtualDevice, maVDRectangle, 2, useLineColor ? 0 : 1); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolygon::setupDiamond() +{ + initialSetup(11, 11, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aPoint1, aPoint2, aPoint3, aPoint4; + OutputDeviceTestCommon::createDiamondPoints(maVDRectangle, 4, aPoint1, aPoint2, aPoint3, aPoint4); + + tools::Polygon aPolygon(4); + + aPolygon.SetPoint(aPoint1, 0); + aPolygon.SetPoint(aPoint2, 1); + aPolygon.SetPoint(aPoint3, 2); + aPolygon.SetPoint(aPoint4, 3); + aPolygon.Optimize(PolyOptimizeFlags::CLOSE); + + mpVirtualDevice->DrawPolygon(aPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolygon::setupLines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + tools::Polygon aHorizontalPolygon(2); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint1, 0); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aHorizontalPolygon); + + tools::Polygon aVerticalPolygon(2); + aVerticalPolygon.SetPoint(aVerticalLinePoint1, 0); + aVerticalPolygon.SetPoint(aVerticalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aVerticalPolygon); + + tools::Polygon aDiagonalPolygon(2); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint1, 0); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aDiagonalPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolygon::setupAALines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetAntialiasing(AntialiasingFlags::EnableB2dDraw); + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + tools::Polygon aHorizontalPolygon(2); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint1, 0); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aHorizontalPolygon); + + tools::Polygon aVerticalPolygon(2); + aVerticalPolygon.SetPoint(aVerticalLinePoint1, 0); + aVerticalPolygon.SetPoint(aVerticalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aVerticalPolygon); + + tools::Polygon aDiagonalPolygon(2); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint1, 0); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint2, 1); + mpVirtualDevice->DrawPolygon(aDiagonalPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/polyline.cxx b/vcl/backendtest/outputdevice/polyline.cxx new file mode 100644 index 000000000..e1d1fd9e0 --- /dev/null +++ b/vcl/backendtest/outputdevice/polyline.cxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test { + +namespace +{ + +void drawPolyLineOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset) +{ + tools::Polygon aPolygon(4); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Top() + nOffset), 0); + aPolygon.SetPoint(Point(rRect.Right() - nOffset, rRect.Top() + nOffset), 1); + aPolygon.SetPoint(Point(rRect.Right() - nOffset, rRect.Bottom() - nOffset), 2); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Bottom() - nOffset), 3); + aPolygon.Optimize(PolyOptimizeFlags::CLOSE); + + rDevice.DrawPolyLine(aPolygon); +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPolyLine::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawPolyLineOffset(*mpVirtualDevice, maVDRectangle, 2); + drawPolyLineOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyLine::setupDiamond() +{ + initialSetup(11, 11, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aPoint1, aPoint2, aPoint3, aPoint4; + OutputDeviceTestCommon::createDiamondPoints(maVDRectangle, 4, aPoint1, aPoint2, aPoint3, aPoint4); + + tools::Polygon aPolygon(4); + + aPolygon.SetPoint(aPoint1, 0); + aPolygon.SetPoint(aPoint2, 1); + aPolygon.SetPoint(aPoint3, 2); + aPolygon.SetPoint(aPoint4, 3); + aPolygon.Optimize(PolyOptimizeFlags::CLOSE); + + mpVirtualDevice->DrawPolyLine(aPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyLine::setupLines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + tools::Polygon aHorizontalPolygon(2); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint1, 0); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aHorizontalPolygon); + + tools::Polygon aVerticalPolygon(2); + aVerticalPolygon.SetPoint(aVerticalLinePoint1, 0); + aVerticalPolygon.SetPoint(aVerticalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aVerticalPolygon); + + tools::Polygon aDiagonalPolygon(2); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint1, 0); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aDiagonalPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyLine::setupAALines() +{ + initialSetup(13, 13, constBackgroundColor); + + mpVirtualDevice->SetAntialiasing(AntialiasingFlags::EnableB2dDraw); + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + Point aHorizontalLinePoint1, aHorizontalLinePoint2; + Point aVerticalLinePoint1, aVerticalLinePoint2; + Point aDiagonalLinePoint1, aDiagonalLinePoint2; + + OutputDeviceTestCommon::createHorizontalVerticalDiagonalLinePoints( + maVDRectangle, aHorizontalLinePoint1, aHorizontalLinePoint2, + aVerticalLinePoint1, aVerticalLinePoint2, + aDiagonalLinePoint1, aDiagonalLinePoint2); + + tools::Polygon aHorizontalPolygon(2); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint1, 0); + aHorizontalPolygon.SetPoint(aHorizontalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aHorizontalPolygon); + + tools::Polygon aVerticalPolygon(2); + aVerticalPolygon.SetPoint(aVerticalLinePoint1, 0); + aVerticalPolygon.SetPoint(aVerticalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aVerticalPolygon); + + tools::Polygon aDiagonalPolygon(2); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint1, 0); + aDiagonalPolygon.SetPoint(aDiagonalLinePoint2, 1); + mpVirtualDevice->DrawPolyLine(aDiagonalPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/polyline_b2d.cxx b/vcl/backendtest/outputdevice/polyline_b2d.cxx new file mode 100644 index 000000000..65658d7ae --- /dev/null +++ b/vcl/backendtest/outputdevice/polyline_b2d.cxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include + +namespace vcl::test +{ +namespace +{ +void drawPolyLineOffset(OutputDevice& rDevice, tools::Rectangle const& rRect, int nOffset) +{ + basegfx::B2DPolygon aPolygon{ + basegfx::B2DPoint(rRect.Left() + nOffset, rRect.Top() + nOffset), + basegfx::B2DPoint(rRect.Right() - nOffset, rRect.Top() + nOffset), + basegfx::B2DPoint(rRect.Right() - nOffset, rRect.Bottom() - nOffset), + basegfx::B2DPoint(rRect.Left() + nOffset, rRect.Bottom() - nOffset), + }; + aPolygon.setClosed(true); + + rDevice.DrawPolyLine(aPolygon, 0.0); // draw hairline +} + +void addDiamondPoints(tools::Rectangle rRect, int nOffset, basegfx::B2DPolygon& rPolygon) +{ + double midPointX = rRect.Left() + (rRect.Right() - rRect.Left()) / 2.0; + double midPointY = rRect.Top() + (rRect.Bottom() - rRect.Top()) / 2.0; + + rPolygon.append({ midPointX, midPointY - nOffset }); + rPolygon.append({ midPointX + nOffset, midPointY }); + rPolygon.append({ midPointX, midPointY + nOffset }); + rPolygon.append({ midPointX - nOffset, midPointY }); +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPolyLineB2D::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawPolyLineOffset(*mpVirtualDevice, maVDRectangle, 2); + drawPolyLineOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmapEx(maVDRectangle.TopLeft(), maVDRectangle.GetSize()) + .GetBitmap(); +} + +Bitmap OutputDeviceTestPolyLineB2D::setupDiamond() +{ + initialSetup(11, 11, constBackgroundColor); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + basegfx::B2DPolygon aPolygon; + addDiamondPoints(maVDRectangle, 4, aPolygon); + aPolygon.setClosed(true); + + mpVirtualDevice->DrawPolyLine(aPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyLineB2D::setupBezier() +{ + initialSetup(21, 21, constBackgroundColor, false); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + basegfx::B2DPolygon aPolygon; + addDiamondPoints(maVDRectangle, 8, aPolygon); + aPolygon.setClosed(true); + + double minX = maVDRectangle.Left() + 4; + double maxX = maVDRectangle.Right() - 4; + double minY = maVDRectangle.Top() + 4; + double maxY = maVDRectangle.Bottom() - 4; + + aPolygon.setControlPoints(0, { minX, minY }, { maxX, minY }); + aPolygon.setControlPoints(1, { maxX, minY }, { maxX, maxY }); + aPolygon.setControlPoints(2, { maxX, maxY }, { minX, maxY }); + aPolygon.setControlPoints(3, { minX, maxY }, { minX, minY }); + + mpVirtualDevice->DrawPolyLine(aPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyLineB2D::setupAABezier() +{ + initialSetup(21, 21, constBackgroundColor, true); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + basegfx::B2DPolygon aPolygon; + addDiamondPoints(maVDRectangle, 8, aPolygon); + aPolygon.setClosed(true); + + double minX = maVDRectangle.Left() + 4; + double maxX = maVDRectangle.Right() - 4; + double minY = maVDRectangle.Top() + 4; + double maxY = maVDRectangle.Bottom() - 4; + + aPolygon.setControlPoints(0, { minX, minY }, { maxX, minY }); + aPolygon.setControlPoints(1, { maxX, minY }, { maxX, maxY }); + aPolygon.setControlPoints(2, { maxX, maxY }, { minX, maxY }); + aPolygon.setControlPoints(3, { minX, maxY }, { minX, minY }); + + mpVirtualDevice->DrawPolyLine(aPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/polypolygon.cxx b/vcl/backendtest/outputdevice/polypolygon.cxx new file mode 100644 index 000000000..a53acbaf7 --- /dev/null +++ b/vcl/backendtest/outputdevice/polypolygon.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + + +namespace vcl::test { + +namespace +{ + +tools::Polygon createPolygonOffset(tools::Rectangle const & rRect, int nOffset, int nFix = 0) +{ + // Note: According to https://lists.freedesktop.org/archives/libreoffice/2019-November/083709.html + // filling polygons always skips the right-most and bottom-most pixels, in order to avoid + // overlaps when drawing adjacent polygons. Specifying nFix = 1 allows to visually compensate + // for this by making the polygon explicitly larger. + tools::Polygon aPolygon(4); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Top() + nOffset), 0); + aPolygon.SetPoint(Point(rRect.Right() - nOffset + nFix, rRect.Top() + nOffset), 1); + aPolygon.SetPoint(Point(rRect.Right() - nOffset + nFix, rRect.Bottom() - nOffset + nFix), 2); + aPolygon.SetPoint(Point(rRect.Left() + nOffset, rRect.Bottom() - nOffset + nFix), 3); + aPolygon.Optimize(PolyOptimizeFlags::CLOSE); + return aPolygon; +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPolyPolygon::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + tools::PolyPolygon aPolyPolygon(2); + aPolyPolygon.Insert(createPolygonOffset(maVDRectangle, 2)); + aPolyPolygon.Insert(createPolygonOffset(maVDRectangle, 5)); + + mpVirtualDevice->DrawPolyPolygon(aPolyPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyPolygon::setupFilledRectangle(bool useLineColor) +{ + initialSetup(13, 13, constBackgroundColor); + + if(useLineColor) + mpVirtualDevice->SetLineColor(constLineColor); + else + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(constFillColor); + + tools::PolyPolygon aPolyPolygon(1); + aPolyPolygon.Insert(createPolygonOffset(maVDRectangle, 2, useLineColor ? 0 : 1)); + + mpVirtualDevice->DrawPolyPolygon(aPolyPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/polypolygon_b2d.cxx b/vcl/backendtest/outputdevice/polypolygon_b2d.cxx new file mode 100644 index 000000000..737cfae19 --- /dev/null +++ b/vcl/backendtest/outputdevice/polypolygon_b2d.cxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test +{ +namespace +{ +basegfx::B2DPolygon createPolygonOffset(tools::Rectangle const& rRect, int nOffset, int nFix = 0) +{ + // Note: According to https://lists.freedesktop.org/archives/libreoffice/2019-November/083709.html + // filling polygons always skips the right-most and bottom-most pixels, in order to avoid + // overlaps when drawing adjacent polygons. Specifying nFix = 1 allows to visually compensate + // for this by making the polygon explicitly larger. + basegfx::B2DPolygon aPolygon{ + basegfx::B2DPoint(rRect.Left() + nOffset, rRect.Top() + nOffset), + basegfx::B2DPoint(rRect.Right() - nOffset + nFix, rRect.Top() + nOffset), + basegfx::B2DPoint(rRect.Right() - nOffset + nFix, rRect.Bottom() - nOffset + nFix), + basegfx::B2DPoint(rRect.Left() + nOffset, rRect.Bottom() - nOffset + nFix), + }; + aPolygon.setClosed(true); + return aPolygon; +} + +} // end anonymous namespace + +Bitmap OutputDeviceTestPolyPolygonB2D::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + basegfx::B2DPolyPolygon aPolyPolygon; + aPolyPolygon.append(createPolygonOffset(maVDRectangle, 2)); + aPolyPolygon.append(createPolygonOffset(maVDRectangle, 5)); + + mpVirtualDevice->DrawPolyPolygon(aPolyPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestPolyPolygonB2D::setupFilledRectangle(bool useLineColor) +{ + initialSetup(13, 13, constBackgroundColor); + + if (useLineColor) + mpVirtualDevice->SetLineColor(constLineColor); + else + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(constFillColor); + + basegfx::B2DPolyPolygon aPolyPolygon( + createPolygonOffset(maVDRectangle, 2, useLineColor ? 0 : 1)); + + mpVirtualDevice->DrawPolyPolygon(aPolyPolygon); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/backendtest/outputdevice/rectangle.cxx b/vcl/backendtest/outputdevice/rectangle.cxx new file mode 100644 index 000000000..8e7c0ba86 --- /dev/null +++ b/vcl/backendtest/outputdevice/rectangle.cxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +namespace vcl::test { + +namespace +{ + void drawRectOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset) + { + rDevice.DrawRect(tools::Rectangle(rRect.Left() + nOffset, rRect.Top() + nOffset, + rRect.Right() - nOffset, rRect.Bottom() - nOffset)); + + } + + void drawInvertOffset(OutputDevice& rDevice, tools::Rectangle const & rRect, int nOffset, InvertFlags eFlags) + { + tools::Rectangle aRectangle(rRect.Left() + nOffset, rRect.Top() + nOffset, + rRect.Right() - nOffset, rRect.Bottom() - nOffset); + rDevice.Invert(aRectangle, eFlags); + } + +} // end anonymous namespace + +Bitmap OutputDeviceTestRect::setupFilledRectangle(bool useLineColor) +{ + initialSetup(13, 13, constBackgroundColor); + + if(useLineColor) + mpVirtualDevice->SetLineColor(constLineColor); + else + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(constFillColor); + + drawRectOffset(*mpVirtualDevice, maVDRectangle, 2); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestRect::setupRectangle(bool bEnableAA) +{ + initialSetup(13, 13, constBackgroundColor, bEnableAA); + + mpVirtualDevice->SetLineColor(constLineColor); + mpVirtualDevice->SetFillColor(); + + drawRectOffset(*mpVirtualDevice, maVDRectangle, 2); + drawRectOffset(*mpVirtualDevice, maVDRectangle, 5); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestRect::setupInvert_NONE() +{ + initialSetup(20, 20, COL_WHITE); + + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(COL_LIGHTRED); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTGREEN); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(10, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTBLUE); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 10), Size(8, 8))); + + drawInvertOffset(*mpVirtualDevice, maVDRectangle, 2, InvertFlags::NONE); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestRect::setupInvert_N50() +{ + initialSetup(20, 20, COL_WHITE); + + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(COL_LIGHTRED); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTGREEN); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(10, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTBLUE); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 10), Size(8, 8))); + + drawInvertOffset(*mpVirtualDevice, maVDRectangle, 2, InvertFlags::N50); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +Bitmap OutputDeviceTestRect::setupInvert_TrackFrame() +{ + initialSetup(20, 20, COL_WHITE); + + mpVirtualDevice->SetLineColor(); + mpVirtualDevice->SetFillColor(COL_LIGHTRED); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTGREEN); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(10, 2), Size(8, 8))); + mpVirtualDevice->SetFillColor(COL_LIGHTBLUE); + mpVirtualDevice->DrawRect(tools::Rectangle(Point(2, 10), Size(8, 8))); + + drawInvertOffset(*mpVirtualDevice, maVDRectangle, 2, InvertFlags::TrackFrame); + + return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize()); +} + +} // end namespace vcl::test + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/commonfuzzer.mk b/vcl/commonfuzzer.mk new file mode 100644 index 000000000..59ec0ff8a --- /dev/null +++ b/vcl/commonfuzzer.mk @@ -0,0 +1,172 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +fuzzer_externals = \ + boost_headers \ + orcus \ + orcus-parser \ + boost_locale \ + boost_filesystem \ + boost_system \ + boost_iostreams \ + curl \ + dtoa \ + harfbuzz \ + graphite \ + cairo \ + fontconfig \ + freetype \ + gpgmepp \ + icui18n \ + icuuc \ + icudata \ + lcms2 \ + librdf \ + libexttextcat \ + liblangtag \ + libxslt \ + libxml2 \ + libjpeg \ + libpng \ + openssl \ + expat \ + mythes \ + hyphen \ + hunspell \ + zlib \ + +fuzzer_core_libraries = \ + basctl \ + avmedia \ + basegfx \ + bib \ + canvastools \ + configmgr \ + cppcanvas \ + ctl \ + dba \ + dbtools \ + deployment \ + deploymentmisc \ + drawinglayer \ + editeng \ + emfio \ + filterconfig \ + fsstorage \ + fwe \ + fwi \ + fwk \ + i18npool \ + i18nutil \ + lng \ + localebe1 \ + mcnttype \ + msfilter \ + package2 \ + sax \ + sb \ + spell \ + sfx \ + sofficeapp \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + emboleobj \ + svgfilter \ + svgio \ + animcore \ + tk \ + tl \ + ucb1 \ + ucbhelper \ + ucpexpand1 \ + ucpfile1 \ + unoxml \ + utl \ + uui \ + vcl \ + xmlscript \ + xo \ + xstor \ + cui \ + chartcontroller \ + chartcore \ + sm \ + gie \ + oox \ + proxyfac \ + reflection \ + odfflatxml \ + invocadapt \ + bootstrap \ + introspection \ + stocservices \ + lnth \ + hyphen \ + i18nsearch \ + embobj \ + evtatt \ + unordf \ + ucphier1 \ + ucptdoc1 \ + srtrs1 \ + storagefd \ + mtfrenderer \ + canvasfactory \ + vclcanvas \ + xof \ + xmlfa \ + xmlfd \ + cppu \ + cppuhelper \ + comphelper \ + i18nlangtag \ + xmlreader \ + unoidl \ + reg \ + store \ + expwrap \ + gcc3_uno \ + salhelper \ + sal \ + +fuzzer_calc_libraries = \ + analysis \ + date \ + pricing \ + scfilt \ + scd \ + vbaevents \ + sc \ + for \ + forui \ + guesslang \ + +fuzzer_writer_libraries = \ + msword \ + sw \ + swd \ + writerfilter \ + wpftwriter \ + textfd \ + guesslang \ + +fuzzer_draw_libraries = \ + sdfilt \ + sd \ + sdd \ + icg \ + guesslang \ + +fuzzer_math_libraries = \ + sm \ + guesslang \ diff --git a/vcl/headless/CustomWidgetDraw.cxx b/vcl/headless/CustomWidgetDraw.cxx new file mode 100644 index 000000000..7c167ff05 --- /dev/null +++ b/vcl/headless/CustomWidgetDraw.cxx @@ -0,0 +1,421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace vcl +{ +WidgetThemeLibrary* CustomWidgetDraw::s_pWidgetImplementation = nullptr; + +CustomWidgetDraw::CustomWidgetDraw(SvpSalGraphics& rGraphics) + : m_rGraphics(rGraphics) +{ +#ifndef DISABLE_DYNLOADING + static bool s_bMissingLibrary = false; + if (!s_pWidgetImplementation && !s_bMissingLibrary) + { + OUString aUrl("${LO_LIB_DIR}/" SVLIBRARY("vcl_widget_theme")); + rtl::Bootstrap::expandMacros(aUrl); + osl::Module aLibrary; + aLibrary.load(aUrl, SAL_LOADMODULE_GLOBAL); + auto fCreateWidgetThemeLibraryFunction + = reinterpret_cast( + aLibrary.getFunctionSymbol("CreateWidgetThemeLibrary")); + aLibrary.release(); + + if (fCreateWidgetThemeLibraryFunction) + s_pWidgetImplementation = (*fCreateWidgetThemeLibraryFunction)(); + + // Init + if (s_pWidgetImplementation) + { + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maNWFData.mbNoFocusRects = true; + pSVData->maNWFData.mbNoFocusRectsForFlatButtons = true; + } + else + s_bMissingLibrary = true; + } +#endif +} + +CustomWidgetDraw::~CustomWidgetDraw() {} + +bool CustomWidgetDraw::isNativeControlSupported(ControlType eType, ControlPart ePart) +{ + return s_pWidgetImplementation + && s_pWidgetImplementation->isNativeControlSupported(eType, ePart); +} + +bool CustomWidgetDraw::hitTestNativeControl(ControlType /*eType*/, ControlPart /*ePart*/, + const tools::Rectangle& /*rBoundingControlRegion*/, + const Point& /*aPos*/, bool& /*rIsInside*/) +{ + return false; +} + +bool CustomWidgetDraw::drawNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rControlRegion, + ControlState eState, const ImplControlValue& rValue, + const OUString& /*aCaptions*/, + const Color& /*rBackgroundColor*/) +{ + if (!s_pWidgetImplementation) + return false; + + bool bOldAA = m_rGraphics.getAntiAliasB2DDraw(); + m_rGraphics.setAntiAliasB2DDraw(true); + + cairo_t* pCairoContext = m_rGraphics.getCairoContext(false); + m_rGraphics.clipRegion(pCairoContext); + + cairo_translate(pCairoContext, rControlRegion.Left(), rControlRegion.Top()); + + long nWidth = rControlRegion.GetWidth(); + long nHeight = rControlRegion.GetHeight(); + + bool bOK = false; + + ControlDrawParameters aParameters{ pCairoContext, ePart, eState }; + + switch (eType) + { + case ControlType::Generic: + { + } + break; + case ControlType::Pushbutton: + { + const PushButtonValue* pPushButtonValue = static_cast(&rValue); + if (pPushButtonValue) + aParameters.bIsAction = pPushButtonValue->mbIsAction; + bOK = s_pWidgetImplementation->drawPushButton(aParameters, nWidth, nHeight); + } + break; + case ControlType::Radiobutton: + { + aParameters.eButtonValue = rValue.getTristateVal(); + bOK = s_pWidgetImplementation->drawRadiobutton(aParameters, nWidth, nHeight); + } + break; + case ControlType::Checkbox: + { + aParameters.eButtonValue = rValue.getTristateVal(); + bOK = s_pWidgetImplementation->drawCheckbox(aParameters, nWidth, nHeight); + } + break; + case ControlType::Combobox: + { + bOK = s_pWidgetImplementation->drawCombobox(aParameters, nWidth, nHeight); + } + break; + case ControlType::Editbox: + { + bOK = s_pWidgetImplementation->drawEditbox(aParameters, nWidth, nHeight); + } + break; + case ControlType::EditboxNoBorder: + { + bOK = s_pWidgetImplementation->drawEditbox(aParameters, nWidth, nHeight); + } + break; + case ControlType::MultilineEditbox: + { + bOK = s_pWidgetImplementation->drawEditbox(aParameters, nWidth, nHeight); + } + break; + case ControlType::Listbox: + { + bOK = s_pWidgetImplementation->drawListbox(aParameters, nWidth, nHeight); + } + break; + case ControlType::Spinbox: + { + if (rValue.getType() == ControlType::SpinButtons) + { + const SpinbuttonValue* pSpinVal = static_cast(&rValue); + + ControlPart upBtnPart = pSpinVal->mnUpperPart; + ControlState upBtnState = pSpinVal->mnUpperState; + + ControlPart downBtnPart = pSpinVal->mnLowerPart; + ControlState downBtnState = pSpinVal->mnLowerState; + { + ControlDrawParameters aParametersUp{ pCairoContext, upBtnPart, upBtnState }; + cairo_save(pCairoContext); + cairo_translate(pCairoContext, + pSpinVal->maUpperRect.Left() - rControlRegion.Left(), + pSpinVal->maUpperRect.Top() - rControlRegion.Top()); + bOK = s_pWidgetImplementation->drawSpinbox(aParametersUp, + pSpinVal->maUpperRect.GetWidth(), + pSpinVal->maUpperRect.GetHeight()); + cairo_restore(pCairoContext); + } + + if (bOK) + { + ControlDrawParameters aParametersDown{ pCairoContext, downBtnPart, + downBtnState }; + cairo_save(pCairoContext); + cairo_translate(pCairoContext, + pSpinVal->maLowerRect.Left() - rControlRegion.Left(), + pSpinVal->maLowerRect.Top() - rControlRegion.Top()); + bOK = s_pWidgetImplementation->drawSpinbox(aParametersDown, + pSpinVal->maLowerRect.GetWidth(), + pSpinVal->maLowerRect.GetHeight()); + cairo_restore(pCairoContext); + } + } + else + { + bOK = s_pWidgetImplementation->drawSpinbox(aParameters, nWidth, nHeight); + } + } + break; + case ControlType::SpinButtons: + { + bOK = s_pWidgetImplementation->drawSpinButtons(aParameters, nWidth, nHeight); + } + break; + case ControlType::TabItem: + { + bOK = s_pWidgetImplementation->drawTabItem(aParameters, nWidth, nHeight); + } + break; + case ControlType::TabPane: + { + bOK = s_pWidgetImplementation->drawTabPane(aParameters, nWidth, nHeight); + } + break; + case ControlType::TabHeader: + { + bOK = s_pWidgetImplementation->drawTabHeader(aParameters, nWidth, nHeight); + } + break; + case ControlType::TabBody: + { + bOK = s_pWidgetImplementation->drawTabBody(aParameters, nWidth, nHeight); + } + break; + case ControlType::Scrollbar: + { + bOK = s_pWidgetImplementation->drawScrollbar(aParameters, nWidth, nHeight); + } + break; + case ControlType::Slider: + { + cairo_save(pCairoContext); + bOK = s_pWidgetImplementation->drawSlider(aParameters, nWidth, nHeight); + cairo_restore(pCairoContext); + + if (bOK) + { + const SliderValue* pSliderValue = static_cast(&rValue); + + ControlDrawParameters aParametersButton{ pCairoContext, ControlPart::Button, + eState | pSliderValue->mnThumbState }; + cairo_save(pCairoContext); + cairo_translate(pCairoContext, + pSliderValue->maThumbRect.Left() - rControlRegion.Left(), + pSliderValue->maThumbRect.Top() - rControlRegion.Top()); + bOK = s_pWidgetImplementation->drawSlider(aParametersButton, + pSliderValue->maThumbRect.GetWidth(), + pSliderValue->maThumbRect.GetHeight()); + cairo_restore(pCairoContext); + } + } + break; + case ControlType::Fixedline: + { + bOK = s_pWidgetImplementation->drawFixedline(aParameters, nWidth, nHeight); + } + break; + case ControlType::Toolbar: + { + bOK = s_pWidgetImplementation->drawToolbar(aParameters, nWidth, nHeight); + } + break; + case ControlType::Menubar: + break; + case ControlType::MenuPopup: + break; + case ControlType::Progress: + { + aParameters.nValue = rValue.getNumericVal(); + bOK = s_pWidgetImplementation->drawProgress(aParameters, nWidth, nHeight); + } + break; + case ControlType::IntroProgress: + break; + case ControlType::Tooltip: + break; + case ControlType::WindowBackground: + { + bOK = s_pWidgetImplementation->drawWindowsBackground(aParameters, nWidth, nHeight); + } + break; + case ControlType::Frame: + { + bOK = s_pWidgetImplementation->drawFrame(aParameters, nWidth, nHeight); + } + break; + case ControlType::ListNode: + { + aParameters.eButtonValue = rValue.getTristateVal(); + bOK = s_pWidgetImplementation->drawListNode(aParameters, nWidth, nHeight); + } + break; + case ControlType::ListNet: + { + bOK = s_pWidgetImplementation->drawListNet(aParameters, nWidth, nHeight); + } + break; + case ControlType::ListHeader: + { + bOK = s_pWidgetImplementation->drawListHeader(aParameters, nWidth, nHeight); + } + break; + } + + basegfx::B2DRange aExtents(rControlRegion.Left(), rControlRegion.Top(), rControlRegion.Right(), + rControlRegion.Bottom()); + + m_rGraphics.releaseCairoContext(pCairoContext, true, aExtents); + + m_rGraphics.setAntiAliasB2DDraw(bOldAA); + + return bOK; +} + +bool CustomWidgetDraw::getNativeControlRegion( + ControlType eType, ControlPart ePart, const tools::Rectangle& rBoundingControlRegion, + ControlState eState, const ImplControlValue& /*aValue*/, const OUString& /*aCaption*/, + tools::Rectangle& rNativeBoundingRegion, tools::Rectangle& rNativeContentRegion) +{ + // Translate to POD rectangle and back. + const rectangle_t aRegion + = { rBoundingControlRegion.getX(), rBoundingControlRegion.getY(), + rBoundingControlRegion.GetWidth(), rBoundingControlRegion.GetHeight() }; + if (s_pWidgetImplementation) + { + rectangle_t aNativeBoundingRegion; + rectangle_t aNativeContentRegion; + s_pWidgetImplementation->getRegion(eType, ePart, eState, aRegion, aNativeBoundingRegion, + aNativeContentRegion); + + rNativeBoundingRegion + = tools::Rectangle(aNativeBoundingRegion.x, aNativeBoundingRegion.y, + aNativeBoundingRegion.width, aNativeBoundingRegion.height); + rNativeContentRegion + = tools::Rectangle(aNativeBoundingRegion.x, aNativeBoundingRegion.y, + aNativeBoundingRegion.width, aNativeBoundingRegion.height); + } + + return false; +} + +bool CustomWidgetDraw::updateSettings(AllSettings& rSettings) +{ + if (!s_pWidgetImplementation) + return false; + + WidgetDrawStyle aStyle; + aStyle.nSize = sizeof(WidgetDrawStyle); + + if (s_pWidgetImplementation->updateSettings(aStyle)) + { + StyleSettings aStyleSet = rSettings.GetStyleSettings(); + + aStyleSet.SetFaceColor(aStyle.maFaceColor); + aStyleSet.SetCheckedColor(aStyle.maCheckedColor); + aStyleSet.SetLightColor(aStyle.maLightColor); + aStyleSet.SetLightBorderColor(aStyle.maLightBorderColor); + aStyleSet.SetShadowColor(aStyle.maShadowColor); + aStyleSet.SetDarkShadowColor(aStyle.maDarkShadowColor); + aStyleSet.SetDefaultButtonTextColor(aStyle.maDefaultButtonTextColor); + aStyleSet.SetButtonTextColor(aStyle.maButtonTextColor); + aStyleSet.SetDefaultActionButtonTextColor(aStyle.maDefaultActionButtonTextColor); + aStyleSet.SetActionButtonTextColor(aStyle.maActionButtonTextColor); + aStyleSet.SetFlatButtonTextColor(aStyle.maFlatButtonTextColor); + aStyleSet.SetDefaultButtonRolloverTextColor(aStyle.maDefaultButtonRolloverTextColor); + aStyleSet.SetButtonRolloverTextColor(aStyle.maButtonRolloverTextColor); + aStyleSet.SetDefaultActionButtonRolloverTextColor( + aStyle.maDefaultActionButtonRolloverTextColor); + aStyleSet.SetActionButtonRolloverTextColor(aStyle.maActionButtonRolloverTextColor); + aStyleSet.SetFlatButtonRolloverTextColor(aStyle.maFlatButtonRolloverTextColor); + aStyleSet.SetDefaultButtonPressedRolloverTextColor( + aStyle.maDefaultButtonPressedRolloverTextColor); + aStyleSet.SetButtonPressedRolloverTextColor(aStyle.maButtonPressedRolloverTextColor); + aStyleSet.SetDefaultActionButtonPressedRolloverTextColor( + aStyle.maDefaultActionButtonPressedRolloverTextColor); + aStyleSet.SetActionButtonPressedRolloverTextColor( + aStyle.maActionButtonPressedRolloverTextColor); + aStyleSet.SetFlatButtonPressedRolloverTextColor( + aStyle.maFlatButtonPressedRolloverTextColor); + aStyleSet.SetRadioCheckTextColor(aStyle.maRadioCheckTextColor); + aStyleSet.SetGroupTextColor(aStyle.maGroupTextColor); + aStyleSet.SetLabelTextColor(aStyle.maLabelTextColor); + aStyleSet.SetWindowColor(aStyle.maWindowColor); + aStyleSet.SetWindowTextColor(aStyle.maWindowTextColor); + aStyleSet.SetDialogColor(aStyle.maDialogColor); + aStyleSet.SetDialogTextColor(aStyle.maDialogTextColor); + aStyleSet.SetWorkspaceColor(aStyle.maWorkspaceColor); + aStyleSet.SetMonoColor(aStyle.maMonoColor); + aStyleSet.SetFieldColor(Color(aStyle.maFieldColor)); + aStyleSet.SetFieldTextColor(aStyle.maFieldTextColor); + aStyleSet.SetFieldRolloverTextColor(aStyle.maFieldRolloverTextColor); + aStyleSet.SetActiveColor(aStyle.maActiveColor); + aStyleSet.SetActiveTextColor(aStyle.maActiveTextColor); + aStyleSet.SetActiveBorderColor(aStyle.maActiveBorderColor); + aStyleSet.SetDeactiveColor(aStyle.maDeactiveColor); + aStyleSet.SetDeactiveTextColor(aStyle.maDeactiveTextColor); + aStyleSet.SetDeactiveBorderColor(aStyle.maDeactiveBorderColor); + aStyleSet.SetMenuColor(aStyle.maMenuColor); + aStyleSet.SetMenuBarColor(aStyle.maMenuBarColor); + aStyleSet.SetMenuBarRolloverColor(aStyle.maMenuBarRolloverColor); + aStyleSet.SetMenuBorderColor(aStyle.maMenuBorderColor); + aStyleSet.SetMenuTextColor(aStyle.maMenuTextColor); + aStyleSet.SetMenuBarTextColor(aStyle.maMenuBarTextColor); + aStyleSet.SetMenuBarRolloverTextColor(aStyle.maMenuBarRolloverTextColor); + aStyleSet.SetMenuBarHighlightTextColor(aStyle.maMenuBarHighlightTextColor); + aStyleSet.SetMenuHighlightColor(aStyle.maMenuHighlightColor); + aStyleSet.SetMenuHighlightTextColor(aStyle.maMenuHighlightTextColor); + aStyleSet.SetHighlightColor(aStyle.maHighlightColor); + aStyleSet.SetHighlightTextColor(aStyle.maHighlightTextColor); + aStyleSet.SetActiveTabColor(aStyle.maActiveTabColor); + aStyleSet.SetInactiveTabColor(aStyle.maInactiveTabColor); + aStyleSet.SetTabTextColor(aStyle.maTabTextColor); + aStyleSet.SetTabRolloverTextColor(aStyle.maTabRolloverTextColor); + aStyleSet.SetTabHighlightTextColor(aStyle.maTabHighlightTextColor); + aStyleSet.SetDisableColor(aStyle.maDisableColor); + aStyleSet.SetHelpColor(aStyle.maHelpColor); + aStyleSet.SetHelpTextColor(aStyle.maHelpTextColor); + aStyleSet.SetLinkColor(aStyle.maLinkColor); + aStyleSet.SetVisitedLinkColor(aStyle.maVisitedLinkColor); + aStyleSet.SetToolTextColor(aStyle.maToolTextColor); + aStyleSet.SetFontColor(aStyle.maFontColor); + + rSettings.SetStyleSettings(aStyleSet); + + return true; + } + + return false; +} + +} // end vcl namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/headlessinst.cxx b/vcl/headless/headlessinst.cxx new file mode 100644 index 000000000..e1694c429 --- /dev/null +++ b/vcl/headless/headlessinst.cxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#include +#include +#include + +class HeadlessSalInstance : public SvpSalInstance +{ +public: + explicit HeadlessSalInstance(std::unique_ptr pMutex); + + virtual SalSystem* CreateSalSystem() override; +}; + +HeadlessSalInstance::HeadlessSalInstance(std::unique_ptr pMutex) + : SvpSalInstance(std::move(pMutex)) +{ +} + +class HeadlessSalSystem : public SvpSalSystem { +public: + HeadlessSalSystem() : SvpSalSystem() {} + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) override + { + (void)rButtons; + SAL_INFO("vcl.headless", + "LibreOffice - dialog '" + << rTitle << "': '" + << rMessage << "'"); + return 0; + } +}; + +SalSystem *HeadlessSalInstance::CreateSalSystem() +{ + return new HeadlessSalSystem(); +} + +class HeadlessSalData : public GenericUnixSalData +{ +public: + explicit HeadlessSalData( SalInstance *pInstance ) : GenericUnixSalData( SAL_DATA_HEADLESS, pInstance ) {} + virtual void ErrorTrapPush() override {} + virtual bool ErrorTrapPop( bool ) override { return false; } +}; + +void SalAbort( const OUString& rErrorText, bool bDumpCore ) +{ + OUString aError( rErrorText ); + if( aError.isEmpty() ) + aError = "Unknown application error"; + + SAL_WARN("vcl.headless", rErrorText); + SAL_INFO("vcl.headless", "SalAbort: '" << aError << "'."); + + if( bDumpCore ) + abort(); + else + _exit(1); +} + +const OUString& SalGetDesktopEnvironment() +{ + static OUString aEnv( "headless" ); + return aEnv; +} + +SalData::SalData() : + m_pInstance( nullptr ), + m_pPIManager( nullptr ) +{ +} + +SalData::~SalData() +{ +} + +// This is our main entry point: +SalInstance *CreateSalInstance() +{ + HeadlessSalInstance* pInstance = new HeadlessSalInstance(std::make_unique()); + new HeadlessSalData( pInstance ); + pInstance->AcquireYieldMutex(); + return pInstance; +} + +void DestroySalInstance( SalInstance *pInst ) +{ + pInst->ReleaseYieldMutexAll(); + delete pInst; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx new file mode 100644 index 000000000..4d881f025 --- /dev/null +++ b/vcl/headless/svpbmp.cxx @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace basegfx; + +SvpSalBitmap::SvpSalBitmap() +: SalBitmap(), + basegfx::SystemDependentDataHolder(), // MM02 + mpDIB() +{ +} + +SvpSalBitmap::~SvpSalBitmap() +{ + Destroy(); +} + +static std::unique_ptr ImplCreateDIB( + const Size& rSize, + sal_uInt16 nBitCount, + const BitmapPalette& rPal) +{ + assert( + (nBitCount == 0 + || nBitCount == 1 + || nBitCount == 4 + || nBitCount == 8 + || nBitCount == 24 + || nBitCount == 32) + && "Unsupported BitCount!"); + + if (!rSize.Width() || !rSize.Height()) + return nullptr; + + std::unique_ptr pDIB; + + try + { + pDIB.reset(new BitmapBuffer); + } + catch (const std::bad_alloc&) + { + return nullptr; + } + + const sal_uInt16 nColors = ( nBitCount <= 8 ) ? ( 1 << nBitCount ) : 0; + + switch (nBitCount) + { + case 1: + pDIB->mnFormat = ScanlineFormat::N1BitLsbPal; + break; + case 4: + pDIB->mnFormat = ScanlineFormat::N4BitMsnPal; + break; + case 8: + pDIB->mnFormat = ScanlineFormat::N8BitPal; + break; + case 24: + pDIB->mnFormat = SVP_24BIT_FORMAT; + break; + default: + nBitCount = 32; + [[fallthrough]]; + case 32: + pDIB->mnFormat = SVP_CAIRO_FORMAT; + break; + } + + pDIB->mnFormat |= ScanlineFormat::TopDown; + pDIB->mnWidth = rSize.Width(); + pDIB->mnHeight = rSize.Height(); + long nScanlineBase; + bool bFail = o3tl::checked_multiply(pDIB->mnWidth, nBitCount, nScanlineBase); + if (bFail) + { + SAL_WARN("vcl.gdi", "checked multiply failed"); + return nullptr; + } + pDIB->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase); + if (pDIB->mnScanlineSize < nScanlineBase/8) + { + SAL_WARN("vcl.gdi", "scanline calculation wraparound"); + return nullptr; + } + pDIB->mnBitCount = nBitCount; + + if( nColors ) + { + pDIB->maPalette = rPal; + pDIB->maPalette.SetEntryCount( nColors ); + } + + size_t size; + bFail = o3tl::checked_multiply(pDIB->mnHeight, pDIB->mnScanlineSize, size); + SAL_WARN_IF(bFail, "vcl.gdi", "checked multiply failed"); + if (bFail || size > SAL_MAX_INT32/2) + { + return nullptr; + } + + try + { + pDIB->mpBits = new sal_uInt8[size]; +#ifdef __SANITIZE_ADDRESS__ + if (!pDIB->mpBits) + { // can only happen with ASAN allocator_may_return_null=1 + pDIB.reset(); + } + else +#endif + { + std::memset(pDIB->mpBits, 0, size); + } + } + catch (const std::bad_alloc&) + { + pDIB.reset(); + } + + return pDIB; +} + +void SvpSalBitmap::Create(std::unique_ptr pBuf) +{ + Destroy(); + mpDIB = std::move(pBuf); +} + +bool SvpSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal) +{ + Destroy(); + mpDIB = ImplCreateDIB( rSize, nBitCount, rPal ); + return mpDIB != nullptr; +} + +bool SvpSalBitmap::Create(const SalBitmap& rBmp) +{ + Destroy(); + + const SvpSalBitmap& rSalBmp = static_cast(rBmp); + + if (rSalBmp.mpDIB) + { + // TODO: reference counting... + mpDIB.reset(new BitmapBuffer( *rSalBmp.mpDIB )); + + const size_t size = mpDIB->mnScanlineSize * mpDIB->mnHeight; + if (size > SAL_MAX_INT32/2) + { + mpDIB.reset(); + return false; + } + + // TODO: get rid of this when BitmapBuffer gets copy constructor + try + { + mpDIB->mpBits = new sal_uInt8[size]; + std::memcpy(mpDIB->mpBits, rSalBmp.mpDIB->mpBits, size); + } + catch (const std::bad_alloc&) + { + mpDIB.reset(); + } + } + + return !rSalBmp.mpDIB || (mpDIB != nullptr); +} + +bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/, + SalGraphics* /*pGraphics*/ ) +{ + return false; +} + +bool SvpSalBitmap::Create( const SalBitmap& /*rSalBmp*/, + sal_uInt16 /*nNewBitCount*/ ) +{ + return false; +} + +bool SvpSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ ) +{ + return false; +} + +void SvpSalBitmap::Destroy() +{ + if (mpDIB) + { + delete[] mpDIB->mpBits; + mpDIB.reset(); + } +} + +Size SvpSalBitmap::GetSize() const +{ + Size aSize; + + if (mpDIB) + { + aSize.setWidth( mpDIB->mnWidth ); + aSize.setHeight( mpDIB->mnHeight ); + } + + return aSize; +} + +sal_uInt16 SvpSalBitmap::GetBitCount() const +{ + sal_uInt16 nBitCount; + + if (mpDIB) + nBitCount = mpDIB->mnBitCount; + else + nBitCount = 0; + + return nBitCount; +} + +BitmapBuffer* SvpSalBitmap::AcquireBuffer(BitmapAccessMode) +{ + return mpDIB.get(); +} + +void SvpSalBitmap::ReleaseBuffer(BitmapBuffer*, BitmapAccessMode nMode) +{ + if( nMode == BitmapAccessMode::Write ) + InvalidateChecksum(); +} + +bool SvpSalBitmap::GetSystemData( BitmapSystemData& ) +{ + return false; +} + +bool SvpSalBitmap::ScalingSupported() const +{ + return false; +} + +bool SvpSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ ) +{ + return false; +} + +bool SvpSalBitmap::Replace( const ::Color& /*rSearchColor*/, const ::Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ ) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpcairotextrender.cxx b/vcl/headless/svpcairotextrender.cxx new file mode 100644 index 000000000..de62b9e50 --- /dev/null +++ b/vcl/headless/svpcairotextrender.cxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +SvpCairoTextRender::SvpCairoTextRender(SvpSalGraphics& rParent) + : mrParent(rParent) +{ +} + +cairo_t* SvpCairoTextRender::getCairoContext() +{ + return mrParent.getCairoContext(false); +} + +void SvpCairoTextRender::getSurfaceOffset(double& nDX, double& nDY) +{ + nDX = 0; + nDY = 0; +} + +void SvpCairoTextRender::clipRegion(cairo_t* cr) +{ + mrParent.clipRegion(cr); +} + +void SvpCairoTextRender::releaseCairoContext(cairo_t* cr) +{ + mrParent.releaseCairoContext(cr, false, basegfx::B2DRange()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpdata.cxx b/vcl/headless/svpdata.cxx new file mode 100644 index 000000000..4ac909c67 --- /dev/null +++ b/vcl/headless/svpdata.cxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +namespace { + +class SvpSalData : public GenericUnixSalData +{ +public: + explicit SvpSalData( SalInstance *pInstance ) : GenericUnixSalData( SAL_DATA_SVP, pInstance ) {} + virtual void ErrorTrapPush() override {} + virtual bool ErrorTrapPop( bool /*bIgnoreError*/ = true ) override { return false; } +}; + +} + +// plugin factory function +SalInstance* svp_create_SalInstance() +{ + SvpSalInstance* pInstance = new SvpSalInstance( std::make_unique() ); + new SvpSalData( pInstance ); + return pInstance; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpdummies.cxx b/vcl/headless/svpdummies.cxx new file mode 100644 index 000000000..548868c05 --- /dev/null +++ b/vcl/headless/svpdummies.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +SvpSalObject::~SvpSalObject() +{ +} + +void SvpSalObject::ResetClipRegion() {} +void SvpSalObject::BeginSetClipRegion( sal_uInt32 ) {} +void SvpSalObject::UnionClipRegion( long, long, long, long ) {} +void SvpSalObject::EndSetClipRegion() {} +void SvpSalObject::SetPosSize( long, long, long, long ) {} +void SvpSalObject::Show( bool ) {} +const SystemEnvData* SvpSalObject::GetSystemData() const { return &m_aSystemChildData; } + +// SalSystem +SvpSalSystem::~SvpSalSystem() {} + +unsigned int SvpSalSystem::GetDisplayScreenCount() +{ + return 1; +} + +tools::Rectangle SvpSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen ) +{ + tools::Rectangle aRect; + if( nScreen == 0 ) + aRect = tools::Rectangle( Point(0,0), Size(VIRTUAL_DESKTOP_WIDTH,VIRTUAL_DESKTOP_HEIGHT) ); + return aRect; +} + +int SvpSalSystem::ShowNativeDialog( const OUString&, const OUString&, + const std::vector< OUString >& ) +{ + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpframe.cxx b/vcl/headless/svpframe.cxx new file mode 100644 index 000000000..0f6da8d28 --- /dev/null +++ b/vcl/headless/svpframe.cxx @@ -0,0 +1,502 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#ifndef IOS +#include +#endif + +#include + +#ifndef IOS +#include +#endif + +SvpSalFrame* SvpSalFrame::s_pFocusFrame = nullptr; + +#ifdef IOS +#define SvpSalGraphics AquaSalGraphics +#endif + +SvpSalFrame::SvpSalFrame( SvpSalInstance* pInstance, + SalFrame* pParent, + SalFrameStyleFlags nSalFrameStyle ) : + m_pInstance( pInstance ), + m_pParent( static_cast(pParent) ), + m_nStyle( nSalFrameStyle ), + m_bVisible( false ), +#ifndef IOS + m_pSurface( nullptr ), +#endif + m_nMinWidth( 0 ), + m_nMinHeight( 0 ), + m_nMaxWidth( 0 ), + m_nMaxHeight( 0 ) +{ + // SAL_DEBUG("SvpSalFrame::SvpSalFrame: " << this); +#ifdef IOS + // Nothing +#elif defined ANDROID + // Nothing +#else + m_aSystemChildData.pSalFrame = this; +#endif + + 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 Children = m_aChildren; + for( auto& rChild : Children ) + rChild->SetParent( m_pParent ); + if( m_pParent ) + m_pParent->m_aChildren.remove( this ); + + if( s_pFocusFrame == this ) + { + // SAL_DEBUG("SvpSalFrame::~SvpSalFrame: losing focus: " << this); + s_pFocusFrame = nullptr; + // call directly here, else an event for a destroyed frame would be dispatched + CallCallback( SalEvent::LoseFocus, nullptr ); + // if the handler has not set a new focus frame + // pass focus to another frame, preferably a document style window + if( s_pFocusFrame == nullptr ) + { + for (auto pSalFrame : m_pInstance->getFrames() ) + { + SvpSalFrame* pFrame = static_cast( pSalFrame ); + if( pFrame->m_bVisible && + pFrame->m_pParent == nullptr && + (pFrame->m_nStyle & (SalFrameStyleFlags::MOVEABLE | + SalFrameStyleFlags::SIZEABLE | + SalFrameStyleFlags::CLOSEABLE) ) + ) + { + pFrame->GetFocus(); + break; + } + } + } + } +#ifndef IOS + if (m_pSurface) + cairo_surface_destroy(m_pSurface); +#endif +} + +void SvpSalFrame::GetFocus() +{ + if( s_pFocusFrame == this ) + return; + + if( (m_nStyle & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT)) == SalFrameStyleFlags::NONE ) + { + if( s_pFocusFrame ) + s_pFocusFrame->LoseFocus(); + // SAL_DEBUG("SvpSalFrame::GetFocus(): " << this); + s_pFocusFrame = this; + m_pInstance->PostEvent( this, nullptr, SalEvent::GetFocus ); + } +} + +void SvpSalFrame::LoseFocus() +{ + if( s_pFocusFrame == this ) + { + // SAL_DEBUG("SvpSalFrame::LoseFocus: " << this); + m_pInstance->PostEvent( this, nullptr, SalEvent::LoseFocus ); + s_pFocusFrame = nullptr; + } +} + +SalGraphics* SvpSalFrame::AcquireGraphics() +{ + SvpSalGraphics* pGraphics = new SvpSalGraphics(); +#ifndef IOS + pGraphics->setSurface(m_pSurface, basegfx::B2IVector(maGeometry.nWidth, maGeometry.nHeight)); +#endif + m_aGraphics.push_back( pGraphics ); + return pGraphics; +} + +void SvpSalFrame::ReleaseGraphics( SalGraphics* pGraphics ) +{ + SvpSalGraphics* pSvpGraphics = dynamic_cast(pGraphics); + m_aGraphics.erase(std::remove(m_aGraphics.begin(), m_aGraphics.end(), pSvpGraphics), m_aGraphics.end()); + delete pSvpGraphics; +} + +bool SvpSalFrame::PostEvent(std::unique_ptr pData) +{ + m_pInstance->PostEvent( this, pData.release(), SalEvent::UserEvent ); + return true; +} + +void SvpSalFrame::PostPaint() const +{ + if( m_bVisible ) + { + SalPaintEvent aPEvt(0, 0, maGeometry.nWidth, maGeometry.nHeight); + aPEvt.mbImmediateUpdate = false; + CallCallback( SalEvent::Paint, &aPEvt ); + } +} + +void SvpSalFrame::SetTitle( const OUString& ) +{ +} + +void SvpSalFrame::SetIcon( sal_uInt16 ) +{ +} + +void SvpSalFrame::SetMenu( SalMenu* ) +{ +} + +void SvpSalFrame::DrawMenuBar() +{ +} + +void SvpSalFrame::SetExtendedFrameStyle( SalExtStyle ) +{ +} + +void SvpSalFrame::Show( bool bVisible, bool bNoActivate ) +{ + if( bVisible && ! m_bVisible ) + { + // SAL_DEBUG("SvpSalFrame::Show: showing: " << this); + m_bVisible = true; + m_pInstance->PostEvent( this, nullptr, SalEvent::Resize ); + if( ! bNoActivate ) + GetFocus(); + } + else if( ! bVisible && m_bVisible ) + { + // SAL_DEBUG("SvpSalFrame::Show: hiding: " << this); + m_bVisible = false; + m_pInstance->PostEvent( this, nullptr, SalEvent::Resize ); + LoseFocus(); + } + else + { + // SAL_DEBUG("SvpSalFrame::Show: nothing: " << this); + } +} + +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, sal_uInt16 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 > o3tl::make_unsigned(m_nMaxWidth) ) + maGeometry.nWidth = m_nMaxWidth; + if( m_nMinWidth > 0 && maGeometry.nWidth < o3tl::make_unsigned(m_nMinWidth) ) + maGeometry.nWidth = m_nMinWidth; + } + if( (nFlags & SAL_FRAME_POSSIZE_HEIGHT) != 0 ) + { + maGeometry.nHeight = nHeight; + if( m_nMaxHeight > 0 && maGeometry.nHeight > o3tl::make_unsigned(m_nMaxHeight) ) + maGeometry.nHeight = m_nMaxHeight; + if( m_nMinHeight > 0 && maGeometry.nHeight < o3tl::make_unsigned(m_nMinHeight) ) + maGeometry.nHeight = m_nMinHeight; + } +#ifndef IOS + basegfx::B2IVector aFrameSize( maGeometry.nWidth, maGeometry.nHeight ); + if (!m_pSurface || cairo_image_surface_get_width(m_pSurface) != aFrameSize.getX() || + cairo_image_surface_get_height(m_pSurface) != aFrameSize.getY() ) + { + if( aFrameSize.getX() == 0 ) + aFrameSize.setX( 1 ); + if( aFrameSize.getY() == 0 ) + aFrameSize.setY( 1 ); + + if (m_pSurface) + cairo_surface_destroy(m_pSurface); + + // Creating backing surfaces for invisible windows costs a big chunk of RAM. + if (Application::IsHeadlessModeEnabled()) + aFrameSize = basegfx::B2IVector( 1, 1 ); + + m_pSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + aFrameSize.getX(), + aFrameSize.getY()); + + // update device in existing graphics + for (auto const& graphic : m_aGraphics) + { + graphic->setSurface(m_pSurface, aFrameSize); + } + } + if( m_bVisible ) + m_pInstance->PostEvent( this, nullptr, SalEvent::Resize ); +#endif +} + +void SvpSalFrame::GetClientSize( long& rWidth, long& rHeight ) +{ + rWidth = maGeometry.nWidth; + rHeight = maGeometry.nHeight; +} + +void SvpSalFrame::GetWorkArea( tools::Rectangle& rRect ) +{ + rRect = tools::Rectangle( Point( 0, 0 ), + Size( VIRTUAL_DESKTOP_WIDTH, VIRTUAL_DESKTOP_HEIGHT ) ); +} + +SalFrame* SvpSalFrame::GetParent() const +{ + return m_pParent; +} + +static constexpr auto FRAMESTATE_MASK_GEOMETRY = + WindowStateMask::X | WindowStateMask::Y | + WindowStateMask::Width | WindowStateMask::Height; + +void SvpSalFrame::SetWindowState( const SalFrameState *pState ) +{ + if (pState == nullptr) + 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 & WindowStateMask::X) + nX = pState->mnX; + if (pState->mnMask & WindowStateMask::Y) + nY = pState->mnY; + if (pState->mnMask & WindowStateMask::Width) + nWidth = pState->mnWidth; + if (pState->mnMask & WindowStateMask::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 = WindowStateState::Normal; + pState->mnX = maGeometry.nX; + pState->mnY = maGeometry.nY; + pState->mnWidth = maGeometry.nWidth; + pState->mnHeight = maGeometry.nHeight; + pState->mnMask = FRAMESTATE_MASK_GEOMETRY | WindowStateMask::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( SalFrameToTop ) +{ + GetFocus(); +} + +void SvpSalFrame::SetPointer( PointerStyle ) +{ +} + +void SvpSalFrame::CaptureMouse( bool ) +{ +} + +void SvpSalFrame::SetPointerPos( long, long ) +{ +} + +void SvpSalFrame::Flush() +{ +} + +void SvpSalFrame::SetInputContext( SalInputContext* ) +{ +} + +void SvpSalFrame::EndExtTextInput( EndExtTextInputFlags ) +{ +} + +OUString SvpSalFrame::GetKeyName( sal_uInt16 ) +{ + return OUString(); +} + +bool SvpSalFrame::MapUnicodeToKeyCode( sal_Unicode, LanguageType, vcl::KeyCode& ) +{ + return false; +} + +LanguageType SvpSalFrame::GetInputLanguage() +{ + return LANGUAGE_DONTKNOW; +} + +void SvpSalFrame::UpdateSettings( AllSettings& rSettings ) +{ + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + + Color aBackgroundColor( 0xef, 0xef, 0xef ); + aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false ); + aStyleSettings.SetMenuColor( aBackgroundColor ); + aStyleSettings.SetMenuBarColor( aBackgroundColor ); + + if (comphelper::LibreOfficeKit::isActive()) // TODO: remove this. + { + vcl::Font aStdFont( FAMILY_SWISS, Size( 0, 14 ) ); + aStdFont.SetCharSet( osl_getThreadTextEncoding() ); + aStdFont.SetWeight( WEIGHT_NORMAL ); + aStdFont.SetFamilyName( "Liberation Sans" ); + aStyleSettings.BatchSetFonts( aStdFont, aStdFont ); + + aStdFont.SetFontSize(Size(0, 12)); + aStyleSettings.SetMenuFont(aStdFont); + + SvpSalGraphics* pGraphics = m_aGraphics.back(); + bool bFreeGraphics = false; + if (!pGraphics) + { + pGraphics = dynamic_cast(AcquireGraphics()); + if (!pGraphics) + { + SAL_WARN("vcl.gtk3", "Could not get graphics - unable to update settings"); + return; + } + bFreeGraphics = true; + } + rSettings.SetStyleSettings(aStyleSettings); +#ifndef IOS // For now... + pGraphics->UpdateSettings(rSettings); +#endif + if (bFreeGraphics) + ReleaseGraphics(pGraphics); + } + else + rSettings.SetStyleSettings(aStyleSettings); +} + +void SvpSalFrame::Beep() +{ +} + +const SystemEnvData* SvpSalFrame::GetSystemData() const +{ + return &m_aSystemChildData; +} + +SalFrame::SalPointerState SvpSalFrame::GetPointerState() +{ + SalPointerState aState; + aState.mnState = 0; + return aState; +} + +KeyIndicatorState SvpSalFrame::GetIndicatorState() +{ + return KeyIndicatorState::NONE; +} + +void SvpSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ ) +{ +} + +void SvpSalFrame::SetParent( SalFrame* pNewParent ) +{ + if( m_pParent ) + m_pParent->m_aChildren.remove( this ); + m_pParent = static_cast(pNewParent); +} + +bool SvpSalFrame::SetPluginParent( SystemParentData* ) +{ + return true; +} + +void SvpSalFrame::ResetClipRegion() +{ +} + +void SvpSalFrame::BeginSetClipRegion( sal_uInt32 ) +{ +} + +void SvpSalFrame::UnionClipRegion( long, long, long, long ) +{ +} + +void SvpSalFrame::EndSetClipRegion() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx new file mode 100644 index 000000000..fadf641fd --- /dev/null +++ b/vcl/headless/svpgdi.cxx @@ -0,0 +1,2622 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ENABLE_CAIRO_CANVAS +# if defined CAIRO_VERSION && CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 10, 0) +# define CAIRO_OPERATOR_DIFFERENCE (static_cast(23)) +# endif +#endif + +namespace +{ + basegfx::B2DRange getClipBox(cairo_t* cr) + { + double x1, y1, x2, y2; + + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + + // support B2DRange::isEmpty() + if(0.0 != x1 || 0.0 != y1 || 0.0 != x2 || 0.0 != y2) + { + return basegfx::B2DRange(x1, y1, x2, y2); + } + + return basegfx::B2DRange(); + } + + basegfx::B2DRange getFillDamage(cairo_t* cr) + { + double x1, y1, x2, y2; + + // this is faster than cairo_fill_extents, at the cost of some overdraw + cairo_path_extents(cr, &x1, &y1, &x2, &y2); + + // support B2DRange::isEmpty() + if(0.0 != x1 || 0.0 != y1 || 0.0 != x2 || 0.0 != y2) + { + return basegfx::B2DRange(x1, y1, x2, y2); + } + + return basegfx::B2DRange(); + } + + basegfx::B2DRange getClippedFillDamage(cairo_t* cr) + { + basegfx::B2DRange aDamageRect(getFillDamage(cr)); + aDamageRect.intersect(getClipBox(cr)); + return aDamageRect; + } + + basegfx::B2DRange getStrokeDamage(cairo_t* cr) + { + double x1, y1, x2, y2; + + // less accurate, but much faster + cairo_path_extents(cr, &x1, &y1, &x2, &y2); + + // support B2DRange::isEmpty() + if(0.0 != x1 || 0.0 != y1 || 0.0 != x2 || 0.0 != y2) + { + return basegfx::B2DRange(x1, y1, x2, y2); + } + + return basegfx::B2DRange(); + } + + basegfx::B2DRange getClippedStrokeDamage(cairo_t* cr) + { + basegfx::B2DRange aDamageRect(getStrokeDamage(cr)); + aDamageRect.intersect(getClipBox(cr)); + return aDamageRect; + } +} + +bool SvpSalGraphics::blendBitmap( const SalTwoRect&, const SalBitmap& /*rBitmap*/ ) +{ + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::blendBitmap case"); + return false; +} + +bool SvpSalGraphics::blendAlphaBitmap( const SalTwoRect&, const SalBitmap&, const SalBitmap&, const SalBitmap& ) +{ + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::blendAlphaBitmap case"); + return false; +} + +namespace +{ + cairo_format_t getCairoFormat(const BitmapBuffer& rBuffer) + { + cairo_format_t nFormat; +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + assert(rBuffer.mnBitCount == 32 || rBuffer.mnBitCount == 24 || rBuffer.mnBitCount == 1); +#else + assert(rBuffer.mnBitCount == 32 || rBuffer.mnBitCount == 1); +#endif + + if (rBuffer.mnBitCount == 32) + nFormat = CAIRO_FORMAT_ARGB32; +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + else if (rBuffer.mnBitCount == 24) + nFormat = CAIRO_FORMAT_RGB24_888; +#endif + else + nFormat = CAIRO_FORMAT_A1; + return nFormat; + } + + void Toggle1BitTransparency(const BitmapBuffer& rBuf) + { + assert(rBuf.maPalette.GetBestIndex(BitmapColor(COL_BLACK)) == 0); + // TODO: make upper layers use standard alpha + if (getCairoFormat(rBuf) == CAIRO_FORMAT_A1) + { + const int nImageSize = rBuf.mnHeight * rBuf.mnScanlineSize; + unsigned char* pDst = rBuf.mpBits; + for (int i = nImageSize; --i >= 0; ++pDst) + *pDst = ~*pDst; + } + } + + std::unique_ptr FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pSrc) + { + if (pSrc == nullptr) + return nullptr; + + assert(pSrc->mnFormat == SVP_24BIT_FORMAT); + const long nWidth = pSrc->mnWidth; + const long nHeight = pSrc->mnHeight; + std::unique_ptr pDst(new BitmapBuffer); + pDst->mnFormat = (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown); + pDst->mnWidth = nWidth; + pDst->mnHeight = nHeight; + pDst->mnBitCount = 32; + pDst->maColorMask = pSrc->maColorMask; + pDst->maPalette = pSrc->maPalette; + + long nScanlineBase; + const bool bFail = o3tl::checked_multiply(pDst->mnBitCount, nWidth, nScanlineBase); + if (bFail) + { + SAL_WARN("vcl.gdi", "checked multiply failed"); + pDst->mpBits = nullptr; + return nullptr; + } + + pDst->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase); + if (pDst->mnScanlineSize < nScanlineBase/8) + { + SAL_WARN("vcl.gdi", "scanline calculation wraparound"); + pDst->mpBits = nullptr; + return nullptr; + } + + try + { + pDst->mpBits = new sal_uInt8[ pDst->mnScanlineSize * nHeight ]; + } + catch (const std::bad_alloc&) + { + // memory exception, clean up + pDst->mpBits = nullptr; + return nullptr; + } + + for (long y = 0; y < nHeight; ++y) + { + sal_uInt8* pS = pSrc->mpBits + y * pSrc->mnScanlineSize; + sal_uInt8* pD = pDst->mpBits + y * pDst->mnScanlineSize; + for (long x = 0; x < nWidth; ++x) + { +#if defined(ANDROID) && !HAVE_FEATURE_ANDROID_LOK + static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcRgba, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra"); + static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb"); + pD[0] = pS[0]; + pD[1] = pS[1]; + pD[2] = pS[2]; + pD[3] = 0xff; // Alpha +#elif defined OSL_BIGENDIAN + static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcArgb, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra"); + static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb"); + pD[0] = 0xff; // Alpha + pD[1] = pS[0]; + pD[2] = pS[1]; + pD[3] = pS[2]; +#else + static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcBgra, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra"); + static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcBgr, "Expected SVP_24BIT_FORMAT set to N24BitTcBgr"); + pD[0] = pS[0]; + pD[1] = pS[1]; + pD[2] = pS[2]; + pD[3] = 0xff; // Alpha +#endif + + pS += 3; + pD += 4; + } + } + + return pDst; + } + + // check for env var that decides for using downscale pattern + static const char* pDisableDownScale(getenv("SAL_DISABLE_CAIRO_DOWNSCALE")); + static bool bDisableDownScale(nullptr != pDisableDownScale); + + class SurfaceHelper + { + private: + cairo_surface_t* pSurface; + std::unordered_map maDownscaled; + + SurfaceHelper(const SurfaceHelper&) = delete; + SurfaceHelper& operator=(const SurfaceHelper&) = delete; + + cairo_surface_t* implCreateOrReuseDownscale( + unsigned long nTargetWidth, + unsigned long nTargetHeight) + { + const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface)); + const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface)); + + // zoomed in, need to stretch at paint, no pre-scale useful + if(nTargetWidth >= nSourceWidth || nTargetHeight >= nSourceHeight) + { + return pSurface; + } + + // calculate downscale factor + unsigned long nWFactor(1); + unsigned long nW((nSourceWidth + 1) / 2); + unsigned long nHFactor(1); + unsigned long nH((nSourceHeight + 1) / 2); + + while(nW > nTargetWidth && nW > 1) + { + nW = (nW + 1) / 2; + nWFactor *= 2; + } + + while(nH > nTargetHeight && nH > 1) + { + nH = (nH + 1) / 2; + nHFactor *= 2; + } + + if(1 == nWFactor && 1 == nHFactor) + { + // original size *is* best binary size, use it + return pSurface; + } + + // go up one scale again - look for no change + nW = (1 == nWFactor) ? nTargetWidth : nW * 2; + nH = (1 == nHFactor) ? nTargetHeight : nH * 2; + + // check if we have a downscaled version of required size + const unsigned long long key((nW * LONG_MAX) + nH); + auto isHit(maDownscaled.find(key)); + + if(isHit != maDownscaled.end()) + { + return isHit->second; + } + + // create new surface in the targeted size + cairo_surface_t* pSurfaceTarget = cairo_surface_create_similar( + pSurface, + cairo_surface_get_content(pSurface), + nW, + nH); + + // did a version to scale self first that worked well, but wouuld've + // been hard to support CAIRO_FORMAT_A1 including bit shifting, so + // I decided to go with cairo itself - use CAIRO_FILTER_FAST or + // CAIRO_FILTER_GOOD though. Please modify as needed for + // performance/quality + cairo_t* cr = cairo_create(pSurfaceTarget); + const double fScaleX(static_cast(nW)/static_cast(nSourceWidth)); + const double fScaleY(static_cast(nH)/static_cast(nSourceHeight)); + cairo_scale(cr, fScaleX, fScaleY); + cairo_set_source_surface(cr, pSurface, 0.0, 0.0); + cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD); + cairo_paint(cr); + cairo_destroy(cr); + + // need to set device_scale for downscale surfaces to get + // them handled correctly + cairo_surface_set_device_scale(pSurfaceTarget, fScaleX, fScaleY); + + // add entry to cached entries + maDownscaled[key] = pSurfaceTarget; + + return pSurfaceTarget; + } + + protected: + cairo_surface_t* implGetSurface() const { return pSurface; } + void implSetSurface(cairo_surface_t* pNew) { pSurface = pNew; } + + bool isTrivial() const + { + constexpr unsigned long nMinimalSquareSizeToBuffer(64*64); + const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface)); + const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface)); + + return nSourceWidth * nSourceHeight < nMinimalSquareSizeToBuffer; + } + + public: + explicit SurfaceHelper() + : pSurface(nullptr), + maDownscaled() + { + } + ~SurfaceHelper() + { + cairo_surface_destroy(pSurface); + for(auto& candidate : maDownscaled) + { + cairo_surface_destroy(candidate.second); + } + } + cairo_surface_t* getSurface( + unsigned long nTargetWidth = 0, + unsigned long nTargetHeight = 0) const + { + if (bDisableDownScale || 0 == nTargetWidth || 0 == nTargetHeight || !pSurface || isTrivial()) + { + // caller asks for original or disabled or trivial (smaller then a minimal square size) + // also excludes zero cases for width/height after this point if need to prescale + return pSurface; + } + + return const_cast(this)->implCreateOrReuseDownscale( + nTargetWidth, + nTargetHeight); + } + }; + + class BitmapHelper : public SurfaceHelper + { + private: +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + const bool m_bForceARGB32; +#endif + SvpSalBitmap aTmpBmp; + + public: + explicit BitmapHelper( + const SalBitmap& rSourceBitmap, + const bool bForceARGB32 = false) + : SurfaceHelper(), +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + m_bForceARGB32(bForceARGB32), +#endif + aTmpBmp() + { + const SvpSalBitmap& rSrcBmp = static_cast(rSourceBitmap); +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + if ((rSrcBmp.GetBitCount() != 32 && rSrcBmp.GetBitCount() != 24) || bForceARGB32) +#else + (void)bForceARGB32; + if (rSrcBmp.GetBitCount() != 32) +#endif + { + //big stupid copy here + const BitmapBuffer* pSrc = rSrcBmp.GetBuffer(); + const SalTwoRect aTwoRect = { 0, 0, pSrc->mnWidth, pSrc->mnHeight, + 0, 0, pSrc->mnWidth, pSrc->mnHeight }; + std::unique_ptr pTmp = (pSrc->mnFormat == SVP_24BIT_FORMAT + ? FastConvert24BitRgbTo32BitCairo(pSrc) + : StretchAndConvert(*pSrc, aTwoRect, SVP_CAIRO_FORMAT)); + aTmpBmp.Create(std::move(pTmp)); + + assert(aTmpBmp.GetBitCount() == 32); + implSetSurface(SvpSalGraphics::createCairoSurface(aTmpBmp.GetBuffer())); + } + else + { + implSetSurface(SvpSalGraphics::createCairoSurface(rSrcBmp.GetBuffer())); + } + } + void mark_dirty() + { + cairo_surface_mark_dirty(implGetSurface()); + } + unsigned char* getBits(sal_Int32 &rStride) + { + cairo_surface_flush(implGetSurface()); + + unsigned char *mask_data = cairo_image_surface_get_data(implGetSurface()); + + const cairo_format_t nFormat = cairo_image_surface_get_format(implGetSurface()); +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + if (!m_bForceARGB32) + assert(nFormat == CAIRO_FORMAT_RGB24_888 && "Expected RGB24_888 image"); + else +#endif + assert(nFormat == CAIRO_FORMAT_ARGB32 && "need to implement CAIRO_FORMAT_A1 after all here"); + + rStride = cairo_format_stride_for_width(nFormat, cairo_image_surface_get_width(implGetSurface())); + + return mask_data; + } + }; + + sal_Int64 estimateUsageInBytesForSurfaceHelper(const SurfaceHelper* pHelper) + { + sal_Int64 nRetval(0); + + if(nullptr != pHelper) + { + cairo_surface_t* pSurface(pHelper->getSurface()); + + if(pSurface) + { + const long nStride(cairo_image_surface_get_stride(pSurface)); + const long nHeight(cairo_image_surface_get_height(pSurface)); + + nRetval = nStride * nHeight; + + // if we do downscale, size will grow by 1/4 + 1/16 + 1/32 + ..., + // rough estimation just multiplies by 1.25, should be good enough + // for estimation of buffer survival time + if(!bDisableDownScale) + { + nRetval = (nRetval * 5) / 4; + } + } + } + + return nRetval; + } + + class SystemDependentData_BitmapHelper : public basegfx::SystemDependentData + { + private: + std::shared_ptr maBitmapHelper; + + public: + SystemDependentData_BitmapHelper( + basegfx::SystemDependentDataManager& rSystemDependentDataManager, + const std::shared_ptr& rBitmapHelper) + : basegfx::SystemDependentData(rSystemDependentDataManager), + maBitmapHelper(rBitmapHelper) + { + } + + const std::shared_ptr& getBitmapHelper() const { return maBitmapHelper; }; + virtual sal_Int64 estimateUsageInBytes() const override; + }; + + sal_Int64 SystemDependentData_BitmapHelper::estimateUsageInBytes() const + { + return estimateUsageInBytesForSurfaceHelper(maBitmapHelper.get()); + } + + class MaskHelper : public SurfaceHelper + { + private: + std::unique_ptr pAlphaBits; + + public: + explicit MaskHelper(const SalBitmap& rAlphaBitmap) + : SurfaceHelper(), + pAlphaBits() + { + const SvpSalBitmap& rMask = static_cast(rAlphaBitmap); + const BitmapBuffer* pMaskBuf = rMask.GetBuffer(); + + if (rAlphaBitmap.GetBitCount() == 8) + { + // the alpha values need to be inverted for Cairo + // so big stupid copy and invert here + const int nImageSize = pMaskBuf->mnHeight * pMaskBuf->mnScanlineSize; + pAlphaBits.reset( new unsigned char[nImageSize] ); + memcpy(pAlphaBits.get(), pMaskBuf->mpBits, nImageSize); + + // TODO: make upper layers use standard alpha + sal_uInt32* pLDst = reinterpret_cast(pAlphaBits.get()); + for( int i = nImageSize/sizeof(sal_uInt32); --i >= 0; ++pLDst ) + *pLDst = ~*pLDst; + assert(reinterpret_cast(pLDst) == pAlphaBits.get()+nImageSize); + + implSetSurface( + cairo_image_surface_create_for_data( + pAlphaBits.get(), + CAIRO_FORMAT_A8, + pMaskBuf->mnWidth, + pMaskBuf->mnHeight, + pMaskBuf->mnScanlineSize)); + } + else + { + // the alpha values need to be inverted for Cairo + // so big stupid copy and invert here + const int nImageSize = pMaskBuf->mnHeight * pMaskBuf->mnScanlineSize; + pAlphaBits.reset( new unsigned char[nImageSize] ); + memcpy(pAlphaBits.get(), pMaskBuf->mpBits, nImageSize); + + const sal_Int32 nBlackIndex = pMaskBuf->maPalette.GetBestIndex(BitmapColor(COL_BLACK)); + if (nBlackIndex == 0) + { + // TODO: make upper layers use standard alpha + unsigned char* pDst = pAlphaBits.get(); + for (int i = nImageSize; --i >= 0; ++pDst) + *pDst = ~*pDst; + } + + implSetSurface( + cairo_image_surface_create_for_data( + pAlphaBits.get(), + CAIRO_FORMAT_A1, + pMaskBuf->mnWidth, + pMaskBuf->mnHeight, + pMaskBuf->mnScanlineSize)); + } + } + }; + + class SystemDependentData_MaskHelper : public basegfx::SystemDependentData + { + private: + std::shared_ptr maMaskHelper; + + public: + SystemDependentData_MaskHelper( + basegfx::SystemDependentDataManager& rSystemDependentDataManager, + const std::shared_ptr& rMaskHelper) + : basegfx::SystemDependentData(rSystemDependentDataManager), + maMaskHelper(rMaskHelper) + { + } + + const std::shared_ptr& getMaskHelper() const { return maMaskHelper; }; + virtual sal_Int64 estimateUsageInBytes() const override; + }; + + sal_Int64 SystemDependentData_MaskHelper::estimateUsageInBytes() const + { + return estimateUsageInBytesForSurfaceHelper(maMaskHelper.get()); + } + + // MM02 decide to use buffers or not + static const char* pDisableMM02Goodies(getenv("SAL_DISABLE_MM02_GOODIES")); + static bool bUseBuffer(nullptr == pDisableMM02Goodies); + static long nMinimalSquareSizeToBuffer(64*64); + + void tryToUseSourceBuffer( + const SalBitmap& rSourceBitmap, + std::shared_ptr& rSurface) + { + // MM02 try to access buffered BitmapHelper + std::shared_ptr pSystemDependentData_BitmapHelper; + const bool bBufferSource(bUseBuffer + && rSourceBitmap.GetSize().Width() * rSourceBitmap.GetSize().Height() > nMinimalSquareSizeToBuffer); + + if(bBufferSource) + { + const SvpSalBitmap& rSrcBmp(static_cast(rSourceBitmap)); + pSystemDependentData_BitmapHelper = rSrcBmp.getSystemDependentData(); + + if(pSystemDependentData_BitmapHelper) + { + // reuse buffered data + rSurface = pSystemDependentData_BitmapHelper->getBitmapHelper(); + } + } + + if(!rSurface) + { + // create data on-demand + rSurface = std::make_shared(rSourceBitmap); + + if(bBufferSource) + { + // add to buffering mechanism to potentially reuse next time + const SvpSalBitmap& rSrcBmp(static_cast(rSourceBitmap)); + rSrcBmp.addOrReplaceSystemDependentData( + ImplGetSystemDependentDataManager(), + rSurface); + } + } + } + + void tryToUseMaskBuffer( + const SalBitmap& rMaskBitmap, + std::shared_ptr& rMask) + { + // MM02 try to access buffered MaskHelper + std::shared_ptr pSystemDependentData_MaskHelper; + const bool bBufferMask(bUseBuffer + && rMaskBitmap.GetSize().Width() * rMaskBitmap.GetSize().Height() > nMinimalSquareSizeToBuffer); + + if(bBufferMask) + { + const SvpSalBitmap& rSrcBmp(static_cast(rMaskBitmap)); + pSystemDependentData_MaskHelper = rSrcBmp.getSystemDependentData(); + + if(pSystemDependentData_MaskHelper) + { + // reuse buffered data + rMask = pSystemDependentData_MaskHelper->getMaskHelper(); + } + } + + if(!rMask) + { + // create data on-demand + rMask = std::make_shared(rMaskBitmap); + + if(bBufferMask) + { + // add to buffering mechanism to potentially reuse next time + const SvpSalBitmap& rSrcBmp(static_cast(rMaskBitmap)); + rSrcBmp.addOrReplaceSystemDependentData( + ImplGetSystemDependentDataManager(), + rMask); + } + } + } +} + +bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap ) +{ + if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap alpha depth case: " << rAlphaBitmap.GetBitCount()); + return false; + } + + // MM02 try to access buffered BitmapHelper + std::shared_ptr aSurface; + tryToUseSourceBuffer(rSourceBitmap, aSurface); + cairo_surface_t* source = aSurface->getSurface( + rTR.mnDestWidth, + rTR.mnDestHeight); + + if (!source) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); + return false; + } + + // MM02 try to access buffered MaskHelper + std::shared_ptr aMask; + tryToUseMaskBuffer(rAlphaBitmap, aMask); + cairo_surface_t *mask = aMask->getSurface( + rTR.mnDestWidth, + rTR.mnDestHeight); + + if (!mask) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); + return false; + } + + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + + cairo_clip(cr); + + cairo_pattern_t* maskpattern = cairo_pattern_create_for_surface(mask); + cairo_translate(cr, rTR.mnDestX, rTR.mnDestY); + double fXScale = static_cast(rTR.mnDestWidth)/rTR.mnSrcWidth; + double fYScale = static_cast(rTR.mnDestHeight)/rTR.mnSrcHeight; + cairo_scale(cr, fXScale, fYScale); + cairo_set_source_surface(cr, source, -rTR.mnSrcX, -rTR.mnSrcY); + + //tdf#114117 when stretching a single pixel width/height source to fit an area + //set extend and filter to stretch it with simplest expected interpolation + if ((fXScale != 1.0 && rTR.mnSrcWidth == 1) || (fYScale != 1.0 && rTR.mnSrcHeight == 1)) + { + cairo_pattern_t* sourcepattern = cairo_get_source(cr); + cairo_pattern_set_extend(sourcepattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(sourcepattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend(maskpattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(maskpattern, CAIRO_FILTER_NEAREST); + } + + //this block is just "cairo_mask_surface", but we have to make it explicit + //because of the cairo_pattern_set_filter etc we may want applied + cairo_matrix_t matrix; + cairo_matrix_init_translate(&matrix, rTR.mnSrcX, rTR.mnSrcY); + cairo_pattern_set_matrix(maskpattern, &matrix); + cairo_mask(cr, maskpattern); + + cairo_pattern_destroy(maskpattern); + + releaseCairoContext(cr, false, extents); + + return true; +} + +bool SvpSalGraphics::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + if (pAlphaBitmap && pAlphaBitmap->GetBitCount() != 8 && pAlphaBitmap->GetBitCount() != 1) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap alpha depth case: " << pAlphaBitmap->GetBitCount()); + return false; + } + + // MM02 try to access buffered BitmapHelper + std::shared_ptr aSurface; + tryToUseSourceBuffer(rSourceBitmap, aSurface); + const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); + const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); + cairo_surface_t* source( + aSurface->getSurface( + nDestWidth, + nDestHeight)); + + if(!source) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case"); + return false; + } + + // MM02 try to access buffered MaskHelper + std::shared_ptr aMask; + if(nullptr != pAlphaBitmap) + { + tryToUseMaskBuffer(*pAlphaBitmap, aMask); + } + + // access cairo_surface_t from MaskHelper + cairo_surface_t* mask(nullptr); + if(aMask) + { + mask = aMask->getSurface( + nDestWidth, + nDestHeight); + } + + if(nullptr != pAlphaBitmap && nullptr == mask) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case"); + return false; + } + + const Size aSize = rSourceBitmap.GetSize(); + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + // setup the image transformation + // using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + cairo_matrix_t matrix; + cairo_matrix_init(&matrix, + aXRel.getX()/aSize.Width(), aXRel.getY()/aSize.Width(), + aYRel.getX()/aSize.Height(), aYRel.getY()/aSize.Height(), + rNull.getX(), rNull.getY()); + + cairo_transform(cr, &matrix); + + cairo_rectangle(cr, 0, 0, aSize.Width(), aSize.Height()); + basegfx::B2DRange extents = getClippedFillDamage(cr); + cairo_clip(cr); + + cairo_set_source_surface(cr, source, 0, 0); + if (mask) + cairo_mask_surface(cr, mask, 0, 0); + else + cairo_paint(cr); + + releaseCairoContext(cr, false, extents); + + return true; +} + +void SvpSalGraphics::clipRegion(cairo_t* cr, const vcl::Region& rClipRegion) +{ + RectangleVector aRectangles; + if (!rClipRegion.IsEmpty()) + { + rClipRegion.GetRegionRectangles(aRectangles); + } + if (!aRectangles.empty()) + { + for (auto const& rectangle : aRectangles) + { + cairo_rectangle(cr, rectangle.Left(), rectangle.Top(), rectangle.GetWidth(), rectangle.GetHeight()); + } + cairo_clip(cr); + } +} + +void SvpSalGraphics::clipRegion(cairo_t* cr) +{ + SvpSalGraphics::clipRegion(cr, m_aClipRegion); +} + +bool SvpSalGraphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency) +{ + const bool bHasFill(m_aFillColor != SALCOLOR_NONE); + const bool bHasLine(m_aLineColor != SALCOLOR_NONE); + + if(!(bHasFill || bHasLine)) + { + return true; + } + + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + const double fTransparency = nTransparency * (1.0/100); + + // To make releaseCairoContext work, use empty extents + basegfx::B2DRange extents; + + if (bHasFill) + { + cairo_rectangle(cr, nX, nY, nWidth, nHeight); + + applyColor(cr, m_aFillColor, fTransparency); + + // set FillDamage + extents = getClippedFillDamage(cr); + + cairo_fill(cr); + } + + if (bHasLine) + { + // PixelOffset used: Set PixelOffset as linear transformation + // Note: Was missing here - probably not by purpose (?) + cairo_matrix_t aMatrix; + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + cairo_set_matrix(cr, &aMatrix); + + cairo_rectangle(cr, nX, nY, nWidth, nHeight); + + applyColor(cr, m_aLineColor, fTransparency); + + // expand with possible StrokeDamage + basegfx::B2DRange stroke_extents = getClippedStrokeDamage(cr); + stroke_extents.transform(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + extents.expand(stroke_extents); + + cairo_stroke(cr); + } + + releaseCairoContext(cr, false, extents); + + return true; +} + +SvpSalGraphics::SvpSalGraphics() + : m_pSurface(nullptr) + , m_fScale(1.0) + , m_aLineColor(Color(0x00, 0x00, 0x00)) + , m_aFillColor(Color(0xFF, 0xFF, 0XFF)) + , m_ePaintMode(PaintMode::Over) + , m_aTextRenderImpl(*this) +{ + bool bLOKActive = comphelper::LibreOfficeKit::isActive(); + if (!initWidgetDrawBackends(bLOKActive)) + { + if (bLOKActive) + m_pWidgetDraw.reset(new vcl::CustomWidgetDraw(*this)); + } +} + +SvpSalGraphics::~SvpSalGraphics() +{ + ReleaseFonts(); +} + +void SvpSalGraphics::setSurface(cairo_surface_t* pSurface, const basegfx::B2IVector& rSize) +{ + m_pSurface = pSurface; + m_aFrameSize = rSize; + dl_cairo_surface_get_device_scale(pSurface, &m_fScale, nullptr); + ResetClipRegion(); +} + +void SvpSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) +{ + rDPIX = rDPIY = 96; +} + +sal_uInt16 SvpSalGraphics::GetBitCount() const +{ + if (cairo_surface_get_content(m_pSurface) != CAIRO_CONTENT_COLOR_ALPHA) + return 1; + return 32; +} + +long SvpSalGraphics::GetGraphicsWidth() const +{ + return m_pSurface ? m_aFrameSize.getX() : 0; +} + +void SvpSalGraphics::ResetClipRegion() +{ + m_aClipRegion.SetNull(); +} + +bool SvpSalGraphics::setClipRegion( const vcl::Region& i_rClip ) +{ + m_aClipRegion = i_rClip; + return true; +} + +void SvpSalGraphics::SetLineColor() +{ + m_aLineColor = SALCOLOR_NONE; +} + +void SvpSalGraphics::SetLineColor( Color nColor ) +{ + m_aLineColor = nColor; +} + +void SvpSalGraphics::SetFillColor() +{ + m_aFillColor = SALCOLOR_NONE; +} + +void SvpSalGraphics::SetFillColor( Color nColor ) +{ + m_aFillColor = nColor; +} + +void SvpSalGraphics::SetXORMode(bool bSet, bool ) +{ + m_ePaintMode = bSet ? PaintMode::Xor : PaintMode::Over; +} + +void SvpSalGraphics::SetROPLineColor( SalROPColor nROPColor ) +{ + switch( nROPColor ) + { + case SalROPColor::N0: + m_aLineColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + m_aLineColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + m_aLineColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void SvpSalGraphics::SetROPFillColor( SalROPColor nROPColor ) +{ + switch( nROPColor ) + { + case SalROPColor::N0: + m_aFillColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + m_aFillColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + m_aFillColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void SvpSalGraphics::drawPixel( long nX, long nY ) +{ + if (m_aLineColor != SALCOLOR_NONE) + { + drawPixel(nX, nY, m_aLineColor); + } +} + +void SvpSalGraphics::drawPixel( long nX, long nY, Color aColor ) +{ + cairo_t* cr = getCairoContext(true); + clipRegion(cr); + + cairo_rectangle(cr, nX, nY, 1, 1); + applyColor(cr, aColor, 0.0); + cairo_fill(cr); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + releaseCairoContext(cr, true, extents); +} + +void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + // because of the -1 hack we have to do fill and draw separately + Color aOrigFillColor = m_aFillColor; + Color aOrigLineColor = m_aLineColor; + m_aFillColor = SALCOLOR_NONE; + m_aLineColor = SALCOLOR_NONE; + + if (aOrigFillColor != SALCOLOR_NONE) + { + basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(nX, nY, nX+nWidth, nY+nHeight)); + m_aFillColor = aOrigFillColor; + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aRect), + 0.0); + + m_aFillColor = SALCOLOR_NONE; + } + + if (aOrigLineColor != SALCOLOR_NONE) + { + // need same -1 hack as X11SalGraphicsImpl::drawRect + basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle( nX, nY, nX+nWidth-1, nY+nHeight-1)); + m_aLineColor = aOrigLineColor; + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aRect), + 0.0); + + m_aLineColor = SALCOLOR_NONE; + } + + m_aFillColor = aOrigFillColor; + m_aLineColor = aOrigLineColor; +} + +void SvpSalGraphics::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + aPoly.setClosed(false); + + drawPolyLine( + basegfx::B2DHomMatrix(), + aPoly, + 0.0, + 1.0, + nullptr, // MM01 + basegfx::B2DLineJoin::Miter, + css::drawing::LineCap_BUTT, + basegfx::deg2rad(15.0) /*default*/, + false); +} + +void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aPoly), + 0.0); +} + +void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly, + const sal_uInt32* pPointCounts, + PCONSTSALPOINT* pPtAry) +{ + basegfx::B2DPolyPolygon aPolyPoly; + for(sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon) + { + sal_uInt32 nPoints = pPointCounts[nPolygon]; + if (nPoints) + { + PCONSTSALPOINT pPoints = pPtAry[nPolygon]; + basegfx::B2DPolygon aPoly; + aPoly.append( basegfx::B2DPoint(pPoints->mnX, pPoints->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint( pPoints[i].mnX, pPoints[i].mnY)); + + aPolyPoly.append(aPoly); + } + } + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + aPolyPoly, + 0.0); +} + +static basegfx::B2DPoint impPixelSnap( + const basegfx::B2DPolygon& rPolygon, + const basegfx::B2DHomMatrix& rObjectToDevice, + basegfx::B2DHomMatrix& rObjectToDeviceInv, + sal_uInt32 nIndex) +{ + const sal_uInt32 nCount(rPolygon.count()); + + // get the data + const basegfx::B2ITuple aPrevTuple(basegfx::fround(rObjectToDevice * rPolygon.getB2DPoint((nIndex + nCount - 1) % nCount))); + const basegfx::B2DPoint aCurrPoint(rObjectToDevice * rPolygon.getB2DPoint(nIndex)); + const basegfx::B2ITuple aCurrTuple(basegfx::fround(aCurrPoint)); + const basegfx::B2ITuple aNextTuple(basegfx::fround(rObjectToDevice * rPolygon.getB2DPoint((nIndex + 1) % nCount))); + + // get the states + const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX()); + const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX()); + const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY()); + const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY()); + const bool bSnapX(bPrevVertical || bNextVertical); + const bool bSnapY(bPrevHorizontal || bNextHorizontal); + + if(bSnapX || bSnapY) + { + basegfx::B2DPoint aSnappedPoint( + bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(), + bSnapY ? aCurrTuple.getY() : aCurrPoint.getY()); + + if(rObjectToDeviceInv.isIdentity()) + { + rObjectToDeviceInv = rObjectToDevice; + rObjectToDeviceInv.invert(); + } + + aSnappedPoint *= rObjectToDeviceInv; + + return aSnappedPoint; + } + + return rPolygon.getB2DPoint(nIndex); +} + +// Remove bClosePath: Checked that the already used mechanism for Win using +// Gdiplus already relies on rPolygon.isClosed(), so should be safe to replace +// this. +// For PixelSnap we need the ObjectToDevice transformation here now. This is a +// special case relative to the also executed LineDraw-Offset of (0.5, 0.5) in +// DeviceCoordinates: The LineDraw-Offset is applied *after* the snap, so we +// need the ObjectToDevice transformation *without* that offset here to do the +// same. The LineDraw-Offset will be applied by the callers using a linear +// transformation for Cairo now +// For support of PixelSnapHairline we also need the ObjectToDevice transformation +// and a method (same as in gdiimpl.cxx for Win and Gdiplus). This is needed e.g. +// for Chart-content visualization. CAUTION: It's not the same as PixelSnap (!) +// tdf#129845 add reply value to allow counting a point/byte/size measurement to +// be included +static size_t AddPolygonToPath( + cairo_t* cr, + const basegfx::B2DPolygon& rPolygon, + const basegfx::B2DHomMatrix& rObjectToDevice, + bool bPixelSnap, + bool bPixelSnapHairline) +{ + // short circuit if there is nothing to do + const sal_uInt32 nPointCount(rPolygon.count()); + size_t nSizeMeasure(0); + + if(0 == nPointCount) + { + return nSizeMeasure; + } + + const bool bHasCurves(rPolygon.areControlPointsUsed()); + const bool bClosePath(rPolygon.isClosed()); + const bool bObjectToDeviceUsed(!rObjectToDevice.isIdentity()); + basegfx::B2DHomMatrix aObjectToDeviceInv; + basegfx::B2DPoint aLast; + + for( sal_uInt32 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 + if(bObjectToDeviceUsed) + { + // go to DeviceCoordinates + aPoint *= rObjectToDevice; + } + + // snap by rounding + aPoint.setX( basegfx::fround( aPoint.getX() ) ); + aPoint.setY( basegfx::fround( aPoint.getY() ) ); + + if(bObjectToDeviceUsed) + { + if(aObjectToDeviceInv.isIdentity()) + { + aObjectToDeviceInv = rObjectToDevice; + aObjectToDeviceInv.invert(); + } + + // go back to ObjectCoordinates + aPoint *= aObjectToDeviceInv; + } + } + + if(bPixelSnapHairline) + { + // snap horizontal and vertical lines (mainly used in Chart for + // 'nicer' AAing) + aPoint = impPixelSnap(rPolygon, rObjectToDevice, aObjectToDeviceInv, nClosedIdx); + } + + if( !nPointIdx ) + { + // first point => just move there + cairo_move_to(cr, aPoint.getX(), aPoint.getY()); + aLast = aPoint; + continue; + } + + bool bPendingCurve(false); + + if( bHasCurves ) + { + bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); + bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); + } + + if( !bPendingCurve ) // line segment + { + cairo_line_to(cr, aPoint.getX(), aPoint.getY()); + nSizeMeasure++; + } + else // cubic bezier segment + { + basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx ); + basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx ); + + // tdf#99165 if the control points are 'empty', create the mathematical + // correct replacement ones to avoid problems with the graphical sub-system + // tdf#101026 The 1st attempt to create a mathematically correct replacement control + // vector was wrong. Best alternative is one as close as possible which means short. + if (aCP1.equal(aLast)) + { + aCP1 = aLast + ((aCP2 - aLast) * 0.0005); + } + + if(aCP2.equal(aPoint)) + { + aCP2 = aPoint + ((aCP1 - aPoint) * 0.0005); + } + + cairo_curve_to(cr, aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), + aPoint.getX(), aPoint.getY()); + // take some bigger measure for curve segments - too expensive to subdivide + // here and that precision not needed, but four (2 points, 2 control-points) + // would be a too low weight + nSizeMeasure += 10; + } + + aLast = aPoint; + } + + if( bClosePath ) + { + cairo_close_path(cr); + } + + return nSizeMeasure; +} + +void SvpSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + basegfx::B2DPolygon aPoly; + + // PixelOffset used: To not mix with possible PixelSnap, cannot do + // directly on coordinates as tried before - despite being already 'snapped' + // due to being integer. If it would be directly added here, it would be + // 'snapped' again when !getAntiAliasB2DDraw(), losing the (0.5, 0.5) offset + aPoly.append(basegfx::B2DPoint(nX1, nY1)); + aPoly.append(basegfx::B2DPoint(nX2, nY2)); + + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + // PixelOffset used: Set PixelOffset as linear transformation + cairo_matrix_t aMatrix; + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + cairo_set_matrix(cr, &aMatrix); + + AddPolygonToPath( + cr, + aPoly, + basegfx::B2DHomMatrix(), + !getAntiAliasB2DDraw(), + false); + + applyColor(cr, m_aLineColor); + + basegfx::B2DRange extents = getClippedStrokeDamage(cr); + extents.transform(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + + cairo_stroke(cr); + + releaseCairoContext(cr, false, extents); +} + +namespace { + +class SystemDependentData_CairoPath : public basegfx::SystemDependentData +{ +private: + // the path data itself + cairo_path_t* mpCairoPath; + + // all other values the path data is based on and + // need to be compared with to check for data validity + bool mbNoJoin; + bool mbAntiAliasB2DDraw; + std::vector< double > maStroke; + +public: + SystemDependentData_CairoPath( + basegfx::SystemDependentDataManager& rSystemDependentDataManager, + size_t nSizeMeasure, + cairo_t* cr, + bool bNoJoin, + bool bAntiAliasB2DDraw, + const std::vector< double >* pStroke); // MM01 + virtual ~SystemDependentData_CairoPath() override; + + // read access + cairo_path_t* getCairoPath() { return mpCairoPath; } + bool getNoJoin() const { return mbNoJoin; } + bool getAntiAliasB2DDraw() const { return mbAntiAliasB2DDraw; } + const std::vector< double >& getStroke() const { return maStroke; } + + virtual sal_Int64 estimateUsageInBytes() const override; +}; + +} + +SystemDependentData_CairoPath::SystemDependentData_CairoPath( + basegfx::SystemDependentDataManager& rSystemDependentDataManager, + size_t nSizeMeasure, + cairo_t* cr, + bool bNoJoin, + bool bAntiAliasB2DDraw, + const std::vector< double >* pStroke) +: basegfx::SystemDependentData(rSystemDependentDataManager), + mpCairoPath(nullptr), + mbNoJoin(bNoJoin), + mbAntiAliasB2DDraw(bAntiAliasB2DDraw), + maStroke() +{ + // tdf#129845 only create a copy of the path when nSizeMeasure is + // bigger than some decent threshold + if(nSizeMeasure > 50) + { + mpCairoPath = cairo_copy_path(cr); + + if(nullptr != pStroke) + { + maStroke = *pStroke; + } + } +} + +SystemDependentData_CairoPath::~SystemDependentData_CairoPath() +{ + if(nullptr != mpCairoPath) + { + cairo_path_destroy(mpCairoPath); + mpCairoPath = nullptr; + } +} + +sal_Int64 SystemDependentData_CairoPath::estimateUsageInBytes() const +{ + // tdf#129845 by using the default return value of zero when no path + // was created, SystemDependentData::calculateCombinedHoldCyclesInSeconds + // will do the right thing and not buffer this entry at all + sal_Int64 nRetval(0); + + if(nullptr != mpCairoPath) + { + // per node + // - num_data incarnations of + // - sizeof(cairo_path_data_t) which is a union of defines and point data + // thus may 2 x sizeof(double) + nRetval = mpCairoPath->num_data * sizeof(cairo_path_data_t); + } + + return nRetval; +} + +bool SvpSalGraphics::drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) +{ + // short circuit if there is nothing to do + if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) + { + return true; + } + + // Wrap call to static version of ::drawPolyLine by + // preparing/getting some local data and parameters + // due to usage in vcl/unx/generic/gdi/salgdi.cxx. + // This is mainly about extended handling of extents + // and the way destruction of CairoContext is handled + // due to current XOR stuff + cairo_t* cr = getCairoContext(false); + basegfx::B2DRange aExtents; + clipRegion(cr); + + bool bRetval( + drawPolyLine( + cr, + &aExtents, + m_aLineColor, + getAntiAliasB2DDraw(), + rObjectToDevice, + rPolyLine, + fTransparency, + fLineWidth, + pStroke, // MM01 + eLineJoin, + eLineCap, + fMiterMinimumAngle, + bPixelSnapHairline)); + + releaseCairoContext(cr, false, aExtents); + + return bRetval; +} + +bool SvpSalGraphics::drawPolyLine( + cairo_t* cr, + basegfx::B2DRange* pExtents, + const Color& rLineColor, + bool bAntiAliasB2DDraw, + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) +{ + // short circuit if there is nothing to do + if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0) + { + return true; + } + + // need to check/handle LineWidth when ObjectToDevice transformation is used + const bool bObjectToDeviceIsIdentity(rObjectToDevice.isIdentity()); + + // tdf#124848 calculate-back logical LineWidth for a hairline + // since this implementation hands over the transformation to + // the graphic sub-system + if(fLineWidth == 0) + { + fLineWidth = 1.0; + + if(!bObjectToDeviceIsIdentity) + { + basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice); + aObjectToDeviceInv.invert(); + fLineWidth = (aObjectToDeviceInv * basegfx::B2DVector(fLineWidth, 0)).getLength(); + } + } + + // PixelOffset used: Need to reflect in linear transformation + cairo_matrix_t aMatrix; + basegfx::B2DHomMatrix aDamageMatrix(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + + if (bObjectToDeviceIsIdentity) + { + // Set PixelOffset as requested + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + } + else + { + // Prepare ObjectToDevice transformation. Take PixelOffset for Lines into + // account: Multiply from left to act in DeviceCoordinates + aDamageMatrix = aDamageMatrix * rObjectToDevice; + cairo_matrix_init( + &aMatrix, + aDamageMatrix.get( 0, 0 ), + aDamageMatrix.get( 1, 0 ), + aDamageMatrix.get( 0, 1 ), + aDamageMatrix.get( 1, 1 ), + aDamageMatrix.get( 0, 2 ), + aDamageMatrix.get( 1, 2 )); + } + + // set linear transformation + cairo_set_matrix(cr, &aMatrix); + + // setup line attributes + cairo_line_join_t eCairoLineJoin = CAIRO_LINE_JOIN_MITER; + switch (eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + eCairoLineJoin = CAIRO_LINE_JOIN_BEVEL; + break; + case basegfx::B2DLineJoin::Round: + eCairoLineJoin = CAIRO_LINE_JOIN_ROUND; + break; + case basegfx::B2DLineJoin::NONE: + case basegfx::B2DLineJoin::Miter: + eCairoLineJoin = CAIRO_LINE_JOIN_MITER; + break; + } + + // convert miter minimum angle to miter limit + double fMiterLimit = 1.0 / sin( fMiterMinimumAngle / 2.0); + + // setup cap attribute + cairo_line_cap_t eCairoLineCap(CAIRO_LINE_CAP_BUTT); + + switch (eLineCap) + { + default: // css::drawing::LineCap_BUTT: + { + eCairoLineCap = CAIRO_LINE_CAP_BUTT; + break; + } + case css::drawing::LineCap_ROUND: + { + eCairoLineCap = CAIRO_LINE_CAP_ROUND; + break; + } + case css::drawing::LineCap_SQUARE: + { + eCairoLineCap = CAIRO_LINE_CAP_SQUARE; + break; + } + } + + cairo_set_source_rgba( + cr, + rLineColor.GetRed()/255.0, + rLineColor.GetGreen()/255.0, + rLineColor.GetBlue()/255.0, + 1.0-fTransparency); + + cairo_set_line_join(cr, eCairoLineJoin); + cairo_set_line_cap(cr, eCairoLineCap); + cairo_set_line_width(cr, fLineWidth); + cairo_set_miter_limit(cr, fMiterLimit); + + // try to access buffered data + std::shared_ptr pSystemDependentData_CairoPath( + rPolyLine.getSystemDependentData()); + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + assert(!bStrokeUsed || (bStrokeUsed && pStroke)); + + // MM01 decide if to stroke directly + static bool bDoDirectCairoStroke(true); + + // MM01 activate to stroke directly + if(bDoDirectCairoStroke && bStrokeUsed) + { + cairo_set_dash(cr, pStroke->data(), pStroke->size(), 0.0); + } + + if(!bDoDirectCairoStroke && pSystemDependentData_CairoPath) + { + // MM01 - check on stroke change. Used against not used, or if both used, + // equal or different? + const bool bStrokeWasUsed(!pSystemDependentData_CairoPath->getStroke().empty()); + + if(bStrokeWasUsed != bStrokeUsed + || (bStrokeUsed && *pStroke != pSystemDependentData_CairoPath->getStroke())) + { + // data invalid, forget + pSystemDependentData_CairoPath.reset(); + } + } + + // check for basegfx::B2DLineJoin::NONE to react accordingly + const bool bNoJoin((basegfx::B2DLineJoin::NONE == eLineJoin + && basegfx::fTools::more(fLineWidth, 0.0))); + + if(pSystemDependentData_CairoPath) + { + // check data validity + if(nullptr == pSystemDependentData_CairoPath->getCairoPath() + || pSystemDependentData_CairoPath->getNoJoin() != bNoJoin + || pSystemDependentData_CairoPath->getAntiAliasB2DDraw() != bAntiAliasB2DDraw + || bPixelSnapHairline /*tdf#124700*/ ) + { + // data invalid, forget + pSystemDependentData_CairoPath.reset(); + } + } + + if(pSystemDependentData_CairoPath) + { + // re-use data + cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); + } + else + { + // create data + size_t nSizeMeasure(0); + + // MM01 need to do line dashing as fallback stuff here now + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(!bDoDirectCairoStroke && bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing or direct stroke, just copy + aPolyPolygonLine.append(rPolyLine); + } + + // MM01 checked/verified for Cairo + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + + if (!bNoJoin) + { + // PixelOffset now reflected in linear transformation used + nSizeMeasure += AddPolygonToPath( + cr, + aPolyLine, + rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset + !bAntiAliasB2DDraw, + bPixelSnapHairline); + } + else + { + const sal_uInt32 nPointCount(aPolyLine.count()); + const sal_uInt32 nEdgeCount(aPolyLine.isClosed() ? nPointCount : nPointCount - 1); + basegfx::B2DPolygon aEdge; + + aEdge.append(aPolyLine.getB2DPoint(0)); + aEdge.append(basegfx::B2DPoint(0.0, 0.0)); + + for (sal_uInt32 i(0); i < nEdgeCount; i++) + { + const sal_uInt32 nNextIndex((i + 1) % nPointCount); + aEdge.setB2DPoint(1, aPolyLine.getB2DPoint(nNextIndex)); + aEdge.setNextControlPoint(0, aPolyLine.getNextControlPoint(i)); + aEdge.setPrevControlPoint(1, aPolyLine.getPrevControlPoint(nNextIndex)); + + // PixelOffset now reflected in linear transformation used + nSizeMeasure += AddPolygonToPath( + cr, + aEdge, + rObjectToDevice, // ObjectToDevice *without* LineDraw-Offset + !bAntiAliasB2DDraw, + bPixelSnapHairline); + + // prepare next step + aEdge.setB2DPoint(0, aEdge.getB2DPoint(1)); + } + } + } + + // copy and add to buffering mechanism + if (!bPixelSnapHairline /*tdf#124700*/) + { + pSystemDependentData_CairoPath = rPolyLine.addOrReplaceSystemDependentData( + ImplGetSystemDependentDataManager(), + nSizeMeasure, + cr, + bNoJoin, + bAntiAliasB2DDraw, + pStroke); + } + } + + // extract extents + if (pExtents) + { + *pExtents = getClippedStrokeDamage(cr); + // transform also extents (ranges) of damage so they can be correctly redrawn + pExtents->transform(aDamageMatrix); + } + + // draw and consume + cairo_stroke(cr); + + return true; +} + +bool SvpSalGraphics::drawPolyLineBezier( sal_uInt32, + const SalPoint*, + const PolyFlags* ) +{ + SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolyLineBezier case"); + return false; +} + +bool SvpSalGraphics::drawPolygonBezier( sal_uInt32, + const SalPoint*, + const PolyFlags* ) +{ + SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolygonBezier case"); + return false; +} + +bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32, + const sal_uInt32*, + const SalPoint* const*, + const PolyFlags* const* ) +{ + SAL_INFO("vcl.gdi", "unsupported SvpSalGraphics::drawPolyPolygonBezier case"); + return false; +} + +namespace +{ + void add_polygon_path(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DHomMatrix& rObjectToDevice, bool bPixelSnap) + { + // try to access buffered data + std::shared_ptr pSystemDependentData_CairoPath( + rPolyPolygon.getSystemDependentData()); + + if(pSystemDependentData_CairoPath) + { + // re-use data + cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath()); + } + else + { + // create data + size_t nSizeMeasure(0); + + for (const auto & rPoly : rPolyPolygon) + { + // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE' + // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset + nSizeMeasure += AddPolygonToPath( + cr, + rPoly, + rObjectToDevice, + bPixelSnap, + false); + } + + // copy and add to buffering mechanism + // for decisions how/what to buffer, see Note in WinSalGraphicsImpl::drawPolyPolygon + pSystemDependentData_CairoPath = rPolyPolygon.addOrReplaceSystemDependentData( + ImplGetSystemDependentDataManager(), + nSizeMeasure, + cr, + false, + false, + nullptr); + } + } +} + +bool SvpSalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ + const bool bHasFill(m_aFillColor != SALCOLOR_NONE); + const bool bHasLine(m_aLineColor != SALCOLOR_NONE); + + if(0 == rPolyPolygon.count() || !(bHasFill || bHasLine) || fTransparency < 0.0 || fTransparency >= 1.0) + { + return true; + } + + cairo_t* cr = getCairoContext(true); + clipRegion(cr); + + // Set full (Object-to-Device) transformation - if used + if(!rObjectToDevice.isIdentity()) + { + cairo_matrix_t aMatrix; + + cairo_matrix_init( + &aMatrix, + rObjectToDevice.get( 0, 0 ), + rObjectToDevice.get( 1, 0 ), + rObjectToDevice.get( 0, 1 ), + rObjectToDevice.get( 1, 1 ), + rObjectToDevice.get( 0, 2 ), + rObjectToDevice.get( 1, 2 )); + cairo_set_matrix(cr, &aMatrix); + } + + // To make releaseCairoContext work, use empty extents + basegfx::B2DRange extents; + + if (bHasFill) + { + add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAliasB2DDraw()); + + applyColor(cr, m_aFillColor, fTransparency); + // Get FillDamage (will be extended for LineDamage below) + extents = getClippedFillDamage(cr); + + cairo_fill(cr); + } + + if (bHasLine) + { + // PixelOffset used: Set PixelOffset as linear transformation + cairo_matrix_t aMatrix; + cairo_matrix_init_translate(&aMatrix, 0.5, 0.5); + cairo_set_matrix(cr, &aMatrix); + + add_polygon_path(cr, rPolyPolygon, rObjectToDevice, !getAntiAliasB2DDraw()); + + applyColor(cr, m_aLineColor, fTransparency); + + // expand with possible StrokeDamage + basegfx::B2DRange stroke_extents = getClippedStrokeDamage(cr); + stroke_extents.transform(basegfx::utils::createTranslateB2DHomMatrix(0.5, 0.5)); + extents.expand(stroke_extents); + + cairo_stroke(cr); + } + + // if transformation has been applied, transform also extents (ranges) + // of damage so they can be correctly redrawn + extents.transform(rObjectToDevice); + releaseCairoContext(cr, true, extents); + + return true; +} + +bool SvpSalGraphics::implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) +{ + cairo_t* cr = getCairoContext(true); + clipRegion(cr); + + basegfx::B2DHomMatrix rObjectToDevice; + + for (auto const & rPolygon : rPolyPolygon) + AddPolygonToPath(cr, rPolygon, rObjectToDevice, !getAntiAliasB2DDraw(), false); + + cairo_pattern_t* pattern; + pattern = cairo_pattern_create_linear(rGradient.maPoint1.getX(), rGradient.maPoint1.getY(), rGradient.maPoint2.getX(), rGradient.maPoint2.getY()); + + for (SalGradientStop const & rStop : rGradient.maStops) + { + double r = rStop.maColor.GetRed() / 255.0; + double g = rStop.maColor.GetGreen() / 255.0; + double b = rStop.maColor.GetBlue() / 255.0; + double a = (0xFF - rStop.maColor.GetTransparency()) / 255.0; + double offset = rStop.mfOffset; + + cairo_pattern_add_color_stop_rgba(pattern, offset, r, g, b, a); + } + cairo_set_source(cr, pattern); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + cairo_fill_preserve(cr); + + releaseCairoContext(cr, true, extents); + + return true; +} + +void SvpSalGraphics::applyColor(cairo_t *cr, Color aColor, double fTransparency) +{ + if (cairo_surface_get_content(m_pSurface) == CAIRO_CONTENT_COLOR_ALPHA) + { + cairo_set_source_rgba(cr, aColor.GetRed()/255.0, + aColor.GetGreen()/255.0, + aColor.GetBlue()/255.0, + 1.0 - fTransparency); + } + else + { + double fSet = aColor == COL_BLACK ? 1.0 : 0.0; + cairo_set_source_rgba(cr, 1, 1, 1, fSet); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + } +} + +void SvpSalGraphics::copyArea( long nDestX, + long nDestY, + long nSrcX, + long nSrcY, + long nSrcWidth, + long nSrcHeight, + bool /*bWindowInvalidate*/ ) +{ + SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight); + copyBits(aTR, this); +} + +static basegfx::B2DRange renderWithOperator(cairo_t* cr, const SalTwoRect& rTR, + cairo_surface_t* source, cairo_operator_t eOperator = CAIRO_OPERATOR_SOURCE) +{ + cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + + cairo_clip(cr); + + cairo_translate(cr, rTR.mnDestX, rTR.mnDestY); + double fXScale = 1.0f; + double fYScale = 1.0f; + if (rTR.mnSrcWidth != 0 && rTR.mnSrcHeight != 0) { + fXScale = static_cast(rTR.mnDestWidth)/rTR.mnSrcWidth; + fYScale = static_cast(rTR.mnDestHeight)/rTR.mnSrcHeight; + cairo_scale(cr, fXScale, fYScale); + } + + cairo_save(cr); + cairo_set_source_surface(cr, source, -rTR.mnSrcX, -rTR.mnSrcY); + if ((fXScale != 1.0 && rTR.mnSrcWidth == 1) || (fYScale != 1.0 && rTR.mnSrcHeight == 1)) + { + cairo_pattern_t* sourcepattern = cairo_get_source(cr); + cairo_pattern_set_extend(sourcepattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(sourcepattern, CAIRO_FILTER_NEAREST); + } + cairo_set_operator(cr, eOperator); + cairo_paint(cr); + cairo_restore(cr); + + return extents; +} + +static basegfx::B2DRange renderSource(cairo_t* cr, const SalTwoRect& rTR, + cairo_surface_t* source) +{ + return renderWithOperator(cr, rTR, source, CAIRO_OPERATOR_SOURCE); +} + +void SvpSalGraphics::copyWithOperator( const SalTwoRect& rTR, cairo_surface_t* source, + cairo_operator_t eOp ) +{ + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + basegfx::B2DRange extents = renderWithOperator(cr, rTR, source, eOp); + + releaseCairoContext(cr, false, extents); +} + +void SvpSalGraphics::copySource( const SalTwoRect& rTR, cairo_surface_t* source ) +{ + copyWithOperator(rTR, source, CAIRO_OPERATOR_SOURCE); +} + +void SvpSalGraphics::copyBits( const SalTwoRect& rTR, + SalGraphics* pSrcGraphics ) +{ + SalTwoRect aTR(rTR); + + SvpSalGraphics* pSrc = pSrcGraphics ? + static_cast(pSrcGraphics) : this; + + cairo_surface_t* source = pSrc->m_pSurface; + + cairo_surface_t *pCopy = nullptr; + if (pSrc == this) + { + //self copy is a problem, so dup source in that case + pCopy = cairo_surface_create_similar(source, + cairo_surface_get_content(m_pSurface), + aTR.mnSrcWidth * m_fScale, + aTR.mnSrcHeight * m_fScale); + dl_cairo_surface_set_device_scale(pCopy, m_fScale, m_fScale); + cairo_t* cr = cairo_create(pCopy); + cairo_set_source_surface(cr, source, -aTR.mnSrcX, -aTR.mnSrcY); + cairo_rectangle(cr, 0, 0, aTR.mnSrcWidth, aTR.mnSrcHeight); + cairo_fill(cr); + cairo_destroy(cr); + + source = pCopy; + + aTR.mnSrcX = 0; + aTR.mnSrcY = 0; + } + + copySource(aTR, source); + + if (pCopy) + cairo_surface_destroy(pCopy); +} + +void SvpSalGraphics::drawBitmap(const SalTwoRect& rTR, const SalBitmap& rSourceBitmap) +{ + // MM02 try to access buffered BitmapHelper + std::shared_ptr aSurface; + tryToUseSourceBuffer(rSourceBitmap, aSurface); + cairo_surface_t* source = aSurface->getSurface( + rTR.mnDestWidth, + rTR.mnDestHeight); + + if (!source) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case"); + return; + } + + copyWithOperator(rTR, source, CAIRO_OPERATOR_OVER); +} + +void SvpSalGraphics::drawBitmap(const SalTwoRect& rTR, const BitmapBuffer* pBuffer, cairo_operator_t eOp) +{ + cairo_surface_t* source = createCairoSurface( pBuffer ); + copyWithOperator(rTR, source, eOp); + cairo_surface_destroy(source); +} + +void SvpSalGraphics::drawBitmap( const SalTwoRect& rTR, + const SalBitmap& rSourceBitmap, + const SalBitmap& rTransparentBitmap ) +{ + drawAlphaBitmap(rTR, rSourceBitmap, rTransparentBitmap); +} + +void SvpSalGraphics::drawMask( const SalTwoRect& rTR, + const SalBitmap& rSalBitmap, + Color nMaskColor ) +{ + /** creates an image from the given rectangle, replacing all black pixels + * with nMaskColor and make all other full transparent */ + // MM02 here decided *against* using buffered BitmapHelper + // because the data gets somehow 'unmuliplied'. This may also be + // done just once, but I am not sure if this is safe to do. + // So for now dispense re-using data here. + BitmapHelper aSurface(rSalBitmap, true); // The mask is argb32 + if (!aSurface.getSurface()) + { + SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawMask case"); + return; + } + sal_Int32 nStride; + unsigned char *mask_data = aSurface.getBits(nStride); + vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table(); + for (long y = rTR.mnSrcY ; y < rTR.mnSrcY + rTR.mnSrcHeight; ++y) + { + unsigned char *row = mask_data + (nStride*y); + unsigned char *data = row + (rTR.mnSrcX * 4); + for (long x = rTR.mnSrcX; x < rTR.mnSrcX + rTR.mnSrcWidth; ++x) + { + sal_uInt8 a = data[SVP_CAIRO_ALPHA]; + sal_uInt8 b = unpremultiply_table[a][data[SVP_CAIRO_BLUE]]; + sal_uInt8 g = unpremultiply_table[a][data[SVP_CAIRO_GREEN]]; + sal_uInt8 r = unpremultiply_table[a][data[SVP_CAIRO_RED]]; + if (r == 0 && g == 0 && b == 0) + { + data[0] = nMaskColor.GetBlue(); + data[1] = nMaskColor.GetGreen(); + data[2] = nMaskColor.GetRed(); + data[3] = 0xff; + } + else + { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + } + data+=4; + } + } + aSurface.mark_dirty(); + + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + cairo_rectangle(cr, rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); + + basegfx::B2DRange extents = getClippedFillDamage(cr); + + cairo_clip(cr); + + cairo_translate(cr, rTR.mnDestX, rTR.mnDestY); + double fXScale = static_cast(rTR.mnDestWidth)/rTR.mnSrcWidth; + double fYScale = static_cast(rTR.mnDestHeight)/rTR.mnSrcHeight; + cairo_scale(cr, fXScale, fYScale); + cairo_set_source_surface(cr, aSurface.getSurface(), -rTR.mnSrcX, -rTR.mnSrcY); + if ((fXScale != 1.0 && rTR.mnSrcWidth == 1) || (fYScale != 1.0 && rTR.mnSrcHeight == 1)) + { + cairo_pattern_t* sourcepattern = cairo_get_source(cr); + cairo_pattern_set_extend(sourcepattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(sourcepattern, CAIRO_FILTER_NEAREST); + } + cairo_paint(cr); + + releaseCairoContext(cr, false, extents); +} + +std::shared_ptr SvpSalGraphics::getBitmap( long nX, long nY, long nWidth, long nHeight ) +{ + std::shared_ptr pBitmap = std::make_shared(); + BitmapPalette aPal; + if (GetBitCount() == 1) + { + aPal.SetEntryCount(2); + aPal[0] = COL_BLACK; + aPal[1] = COL_WHITE; + } + + if (!pBitmap->Create(Size(nWidth, nHeight), GetBitCount(), aPal)) + { + SAL_WARN("vcl.gdi", "SvpSalGraphics::getBitmap, cannot create bitmap"); + return nullptr; + } + + cairo_surface_t* target = SvpSalGraphics::createCairoSurface(pBitmap->GetBuffer()); + if (!target) + { + SAL_WARN("vcl.gdi", "SvpSalGraphics::getBitmap, cannot create cairo surface"); + return nullptr; + } + cairo_t* cr = cairo_create(target); + + SalTwoRect aTR(nX, nY, nWidth, nHeight, 0, 0, nWidth, nHeight); + renderSource(cr, aTR, m_pSurface); + + cairo_destroy(cr); + cairo_surface_destroy(target); + + Toggle1BitTransparency(*pBitmap->GetBuffer()); + + return pBitmap; +} + +Color SvpSalGraphics::getPixel( long nX, long nY ) +{ +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + cairo_surface_t *target = cairo_surface_create_similar_image(m_pSurface, CAIRO_FORMAT_ARGB32, 1, 1); +#else + cairo_surface_t *target = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); +#endif + + cairo_t* cr = cairo_create(target); + + cairo_rectangle(cr, 0, 0, 1, 1); + cairo_set_source_surface(cr, m_pSurface, -nX, -nY); + cairo_paint(cr); + cairo_destroy(cr); + + cairo_surface_flush(target); + vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table(); + unsigned char *data = cairo_image_surface_get_data(target); + sal_uInt8 a = data[SVP_CAIRO_ALPHA]; + sal_uInt8 b = unpremultiply_table[a][data[SVP_CAIRO_BLUE]]; + sal_uInt8 g = unpremultiply_table[a][data[SVP_CAIRO_GREEN]]; + sal_uInt8 r = unpremultiply_table[a][data[SVP_CAIRO_RED]]; + Color aColor(0xFF - a, r, g, b); + cairo_surface_destroy(target); + + return aColor; +} + +namespace +{ + cairo_pattern_t * create_stipple() + { + static unsigned char data[16] = { 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x00, 0xFF, 0xFF }; + cairo_surface_t* surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_A8, 4, 4, 4); + cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface); + cairo_surface_destroy(surface); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); + return pattern; + } +} + +void SvpSalGraphics::invert(const basegfx::B2DPolygon &rPoly, SalInvert nFlags) +{ + cairo_t* cr = getCairoContext(false); + clipRegion(cr); + + // To make releaseCairoContext work, use empty extents + basegfx::B2DRange extents; + + AddPolygonToPath( + cr, + rPoly, + basegfx::B2DHomMatrix(), + !getAntiAliasB2DDraw(), + false); + + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + + if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 10, 0)) + { + cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE); + } + else + { + SAL_WARN("vcl.gdi", "SvpSalGraphics::invert, archaic cairo"); + } + + if (nFlags & SalInvert::TrackFrame) + { + cairo_set_line_width(cr, 2.0); + const double dashLengths[2] = { 4.0, 4.0 }; + cairo_set_dash(cr, dashLengths, 2, 0); + + extents = getClippedStrokeDamage(cr); + //see tdf#106577 under wayland, some pixel droppings seen, maybe we're + //out by one somewhere, or cairo_stroke_extents is confused by + //dashes/line width + if(!extents.isEmpty()) + { + extents.grow(1); + } + + cairo_stroke(cr); + } + else + { + extents = getClippedFillDamage(cr); + + cairo_clip(cr); + + if (nFlags & SalInvert::N50) + { + cairo_pattern_t *pattern = create_stipple(); + cairo_surface_t* surface = cairo_surface_create_similar(m_pSurface, + cairo_surface_get_content(m_pSurface), + extents.getWidth() * m_fScale, + extents.getHeight() * m_fScale); + + dl_cairo_surface_set_device_scale(surface, m_fScale, m_fScale); + cairo_t* stipple_cr = cairo_create(surface); + cairo_set_source_rgb(stipple_cr, 1.0, 1.0, 1.0); + cairo_mask(stipple_cr, pattern); + cairo_pattern_destroy(pattern); + cairo_destroy(stipple_cr); + cairo_mask_surface(cr, surface, extents.getMinX(), extents.getMinY()); + cairo_surface_destroy(surface); + } + else + { + cairo_paint(cr); + } + } + + releaseCairoContext(cr, false, extents); +} + +void SvpSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) +{ + basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(nX, nY, nX+nWidth, nY+nHeight)); + + invert(aRect, nFlags); +} + +void SvpSalGraphics::invert(sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags) +{ + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + aPoly.setClosed(true); + + invert(aPoly, nFlags); +} + +bool SvpSalGraphics::drawEPS( long, long, long, long, void*, sal_uInt32 ) +{ + return false; +} + +namespace +{ + bool isCairoCompatible(const BitmapBuffer* pBuffer) + { + if (!pBuffer) + return false; + + // We use Cairo that supports 24-bit RGB. +#ifdef HAVE_CAIRO_FORMAT_RGB24_888 + if (pBuffer->mnBitCount != 32 && pBuffer->mnBitCount != 24 && pBuffer->mnBitCount != 1) +#else + if (pBuffer->mnBitCount != 32 && pBuffer->mnBitCount != 1) +#endif + return false; + + cairo_format_t nFormat = getCairoFormat(*pBuffer); + return (cairo_format_stride_for_width(nFormat, pBuffer->mnWidth) == pBuffer->mnScanlineSize); + } +} + +cairo_surface_t* SvpSalGraphics::createCairoSurface(const BitmapBuffer *pBuffer) +{ + if (!isCairoCompatible(pBuffer)) + return nullptr; + + cairo_format_t nFormat = getCairoFormat(*pBuffer); + cairo_surface_t *target = + cairo_image_surface_create_for_data(pBuffer->mpBits, + nFormat, + pBuffer->mnWidth, pBuffer->mnHeight, + pBuffer->mnScanlineSize); + if (cairo_surface_status(target) != CAIRO_STATUS_SUCCESS) + { + cairo_surface_destroy(target); + return nullptr; + } + return target; +} + +cairo_t* SvpSalGraphics::createTmpCompatibleCairoContext() const +{ +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + cairo_surface_t *target = cairo_surface_create_similar_image(m_pSurface, +#else + cairo_surface_t *target = cairo_image_surface_create( +#endif + CAIRO_FORMAT_ARGB32, + m_aFrameSize.getX() * m_fScale, + m_aFrameSize.getY() * m_fScale); + + dl_cairo_surface_set_device_scale(target, m_fScale, m_fScale); + + return cairo_create(target); +} + +cairo_t* SvpSalGraphics::getCairoContext(bool bXorModeAllowed) const +{ + cairo_t* cr; + if (m_ePaintMode == PaintMode::Xor && bXorModeAllowed) + cr = createTmpCompatibleCairoContext(); + else + cr = cairo_create(m_pSurface); + cairo_set_line_width(cr, 1); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_antialias(cr, getAntiAliasB2DDraw() ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + // ensure no linear transformation and no PathInfo in local cairo_path_t + cairo_identity_matrix(cr); + cairo_new_path(cr); + + return cr; +} + +cairo_user_data_key_t* SvpSalGraphics::getDamageKey() +{ + static cairo_user_data_key_t aDamageKey; + return &aDamageKey; +} + +void SvpSalGraphics::releaseCairoContext(cairo_t* cr, bool bXorModeAllowed, const basegfx::B2DRange& rExtents) const +{ + const bool bXoring = (m_ePaintMode == PaintMode::Xor && bXorModeAllowed); + + if (rExtents.isEmpty()) + { + //nothing changed, return early + if (bXoring) + { + cairo_surface_t* surface = cairo_get_target(cr); + cairo_surface_destroy(surface); + } + cairo_destroy(cr); + return; + } + + basegfx::B2IRange aIntExtents(basegfx::unotools::b2ISurroundingRangeFromB2DRange(rExtents)); + sal_Int32 nExtentsLeft(aIntExtents.getMinX()), nExtentsTop(aIntExtents.getMinY()); + sal_Int32 nExtentsRight(aIntExtents.getMaxX()), nExtentsBottom(aIntExtents.getMaxY()); + sal_Int32 nWidth = m_aFrameSize.getX(); + sal_Int32 nHeight = m_aFrameSize.getY(); + nExtentsLeft = std::max(nExtentsLeft, 0); + nExtentsTop = std::max(nExtentsTop, 0); + nExtentsRight = std::min(nExtentsRight, nWidth); + nExtentsBottom = std::min(nExtentsBottom, nHeight); + + cairo_surface_t* surface = cairo_get_target(cr); + cairo_surface_flush(surface); + + //For the most part we avoid the use of XOR these days, but there + //are some edge cases where legacy stuff still supports it, so + //emulate it (slowly) here. + if (bXoring) + { + cairo_surface_t* target_surface = m_pSurface; + if (cairo_surface_get_type(target_surface) != CAIRO_SURFACE_TYPE_IMAGE) + { + //in the unlikely case we can't use m_pSurface directly, copy contents + //to another temp image surface + cairo_t* copycr = createTmpCompatibleCairoContext(); + cairo_rectangle(copycr, nExtentsLeft, nExtentsTop, + nExtentsRight - nExtentsLeft, + nExtentsBottom - nExtentsTop); + cairo_set_source_surface(copycr, m_pSurface, 0, 0); + cairo_paint(copycr); + target_surface = cairo_get_target(copycr); + cairo_destroy(copycr); + } + + cairo_surface_flush(target_surface); + unsigned char *target_surface_data = cairo_image_surface_get_data(target_surface); + unsigned char *xor_surface_data = cairo_image_surface_get_data(surface); + + cairo_format_t nFormat = cairo_image_surface_get_format(target_surface); + assert(nFormat == CAIRO_FORMAT_ARGB32 && "need to implement CAIRO_FORMAT_A1 after all here"); + sal_Int32 nStride = cairo_format_stride_for_width(nFormat, nWidth * m_fScale); + sal_Int32 nUnscaledExtentsLeft = nExtentsLeft * m_fScale; + sal_Int32 nUnscaledExtentsRight = nExtentsRight * m_fScale; + sal_Int32 nUnscaledExtentsTop = nExtentsTop * m_fScale; + sal_Int32 nUnscaledExtentsBottom = nExtentsBottom * m_fScale; + vcl::bitmap::lookup_table unpremultiply_table = vcl::bitmap::get_unpremultiply_table(); + vcl::bitmap::lookup_table premultiply_table = vcl::bitmap::get_premultiply_table(); + for (sal_Int32 y = nUnscaledExtentsTop; y < nUnscaledExtentsBottom; ++y) + { + unsigned char *true_row = target_surface_data + (nStride*y); + unsigned char *xor_row = xor_surface_data + (nStride*y); + unsigned char *true_data = true_row + (nUnscaledExtentsLeft * 4); + unsigned char *xor_data = xor_row + (nUnscaledExtentsLeft * 4); + for (sal_Int32 x = nUnscaledExtentsLeft; x < nUnscaledExtentsRight; ++x) + { + sal_uInt8 a = true_data[SVP_CAIRO_ALPHA]; + sal_uInt8 xor_a = xor_data[SVP_CAIRO_ALPHA]; + sal_uInt8 b = unpremultiply_table[a][true_data[SVP_CAIRO_BLUE]] ^ + unpremultiply_table[xor_a][xor_data[SVP_CAIRO_BLUE]]; + sal_uInt8 g = unpremultiply_table[a][true_data[SVP_CAIRO_GREEN]] ^ + unpremultiply_table[xor_a][xor_data[SVP_CAIRO_GREEN]]; + sal_uInt8 r = unpremultiply_table[a][true_data[SVP_CAIRO_RED]] ^ + unpremultiply_table[xor_a][xor_data[SVP_CAIRO_RED]]; + true_data[SVP_CAIRO_BLUE] = premultiply_table[a][b]; + true_data[SVP_CAIRO_GREEN] = premultiply_table[a][g]; + true_data[SVP_CAIRO_RED] = premultiply_table[a][r]; + true_data+=4; + xor_data+=4; + } + } + cairo_surface_mark_dirty(target_surface); + + if (target_surface != m_pSurface) + { + cairo_t* copycr = cairo_create(m_pSurface); + //unlikely case we couldn't use m_pSurface directly, copy contents + //back from image surface + cairo_rectangle(copycr, nExtentsLeft, nExtentsTop, + nExtentsRight - nExtentsLeft, + nExtentsBottom - nExtentsTop); + cairo_set_source_surface(copycr, target_surface, 0, 0); + cairo_paint(copycr); + cairo_destroy(copycr); + cairo_surface_destroy(target_surface); + } + + cairo_surface_destroy(surface); + } + + cairo_destroy(cr); // unref + + DamageHandler* pDamage = static_cast(cairo_surface_get_user_data(m_pSurface, getDamageKey())); + + if (pDamage) + { + pDamage->damaged(pDamage->handle, nExtentsLeft, nExtentsTop, + nExtentsRight - nExtentsLeft, + nExtentsBottom - nExtentsTop); + } +} + +#if ENABLE_CAIRO_CANVAS +bool SvpSalGraphics::SupportsCairo() const +{ + return false; +} + +cairo::SurfaceSharedPtr SvpSalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& /*rSurface*/) const +{ + return cairo::SurfaceSharedPtr(); +} + +cairo::SurfaceSharedPtr SvpSalGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int /*x*/, int /*y*/, int /*width*/, int /*height*/) const +{ + return cairo::SurfaceSharedPtr(); +} + +cairo::SurfaceSharedPtr SvpSalGraphics::CreateBitmapSurface(const OutputDevice& /*rRefDevice*/, const BitmapSystemData& /*rData*/, const Size& /*rSize*/) const +{ + return cairo::SurfaceSharedPtr(); +} + +css::uno::Any SvpSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*rSurface*/, const basegfx::B2ISize& /*rSize*/) const +{ + return css::uno::Any(); +} + +#endif // ENABLE_CAIRO_CANVAS + +SystemGraphicsData SvpSalGraphics::GetGraphicsData() const +{ + return SystemGraphicsData(); +} + +bool SvpSalGraphics::supportsOperation(OutDevSupportType eType) const +{ + switch (eType) + { + case OutDevSupportType::TransparentRect: + case OutDevSupportType::B2DDraw: + return true; + } + return false; +} + +void dl_cairo_surface_set_device_scale(cairo_surface_t *surface, double x_scale, double y_scale) +{ +#ifdef ANDROID + cairo_surface_set_device_scale(surface, x_scale, y_scale); +#else + static auto func = reinterpret_cast( + dlsym(nullptr, "cairo_surface_set_device_scale")); + if (func) + func(surface, x_scale, y_scale); +#endif +} + +void dl_cairo_surface_get_device_scale(cairo_surface_t *surface, double* x_scale, double* y_scale) +{ +#ifdef ANDROID + cairo_surface_get_device_scale(surface, x_scale, y_scale); +#else + static auto func = reinterpret_cast( + dlsym(nullptr, "cairo_surface_get_device_scale")); + if (func) + func(surface, x_scale, y_scale); + else + { + if (x_scale) + *x_scale = 1.0; + if (y_scale) + *y_scale = 1.0; + } +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpinst.cxx b/vcl/headless/svpinst.cxx new file mode 100644 index 000000000..daaa4d170 --- /dev/null +++ b/vcl/headless/svpinst.cxx @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#if HAVE_FEATURE_UI +# include +#endif + +#include +#include +#include +#include +#ifdef IOS +#include +#include +#include +#else +#include +#endif +#include + +#include +#include +#include +// FIXME: remove when we re-work the svp mainloop +#include +#include + +SvpSalInstance* SvpSalInstance::s_pDefaultInstance = nullptr; + +#if !defined(ANDROID) && !defined(IOS) + +static void atfork_child() +{ + if (SvpSalInstance::s_pDefaultInstance != nullptr) + { + SvpSalInstance::s_pDefaultInstance->CloseWakeupPipe(false); + SvpSalInstance::s_pDefaultInstance->CreateWakeupPipe(false); + } +} + +#endif + +SvpSalInstance::SvpSalInstance( std::unique_ptr pMutex ) + : SalGenericInstance( std::move(pMutex) ) +{ + m_aTimeout.tv_sec = 0; + m_aTimeout.tv_usec = 0; + m_nTimeoutMS = 0; + + m_MainThread = osl::Thread::getCurrentIdentifier(); + CreateWakeupPipe(true); + if( s_pDefaultInstance == nullptr ) + s_pDefaultInstance = this; +#if !defined(ANDROID) && !defined(IOS) + pthread_atfork(nullptr, nullptr, atfork_child); +#endif +} + +SvpSalInstance::~SvpSalInstance() +{ + if( s_pDefaultInstance == this ) + s_pDefaultInstance = nullptr; + CloseWakeupPipe(true); +} + +void SvpSalInstance::CloseWakeupPipe(bool log) +{ + SvpSalYieldMutex *const pMutex(dynamic_cast(GetYieldMutex())); + if (!pMutex) + return; + if (pMutex->m_FeedbackFDs[0] != -1) + { + if (log) + { + SAL_INFO("vcl.headless", "CloseWakeupPipe: Closing inherited feedback pipe: [" << pMutex->m_FeedbackFDs[0] << "," << pMutex->m_FeedbackFDs[1] << "]"); + } + close (pMutex->m_FeedbackFDs[0]); + close (pMutex->m_FeedbackFDs[1]); + pMutex->m_FeedbackFDs[0] = pMutex->m_FeedbackFDs[1] = -1; + } +} + +void SvpSalInstance::CreateWakeupPipe(bool log) +{ + SvpSalYieldMutex *const pMutex(dynamic_cast(GetYieldMutex())); + if (!pMutex) + return; + if (pipe (pMutex->m_FeedbackFDs) == -1) + { + if (log) + { + SAL_WARN("vcl.headless", "Could not create feedback pipe: " << strerror(errno)); + std::abort(); + } + } + else + { + if (log) + { + SAL_INFO("vcl.headless", "CreateWakeupPipe: Created feedback pipe: [" << pMutex->m_FeedbackFDs[0] << "," << pMutex->m_FeedbackFDs[1] << "]"); + } + + int flags; + + // set close-on-exec descriptor flag. + if ((flags = fcntl (pMutex->m_FeedbackFDs[0], F_GETFD)) != -1) + { + flags |= FD_CLOEXEC; + (void) fcntl(pMutex->m_FeedbackFDs[0], F_SETFD, flags); + } + if ((flags = fcntl (pMutex->m_FeedbackFDs[1], F_GETFD)) != -1) + { + flags |= FD_CLOEXEC; + (void) fcntl(pMutex->m_FeedbackFDs[1], F_SETFD, flags); + } + + // retain the default blocking I/O for feedback pipe + } +} + +void SvpSalInstance::TriggerUserEventProcessing() +{ + Wakeup(); +} + +#ifndef NDEBUG +static bool g_CheckedMutex = false; +#endif + +void SvpSalInstance::Wakeup(SvpRequest const request) +{ +#ifndef NDEBUG + if (!g_CheckedMutex) + { + assert(dynamic_cast(GetYieldMutex()) != nullptr + && "This SvpSalInstance function requires use of SvpSalYieldMutex"); + g_CheckedMutex = true; + } +#endif + + ImplSVData* pSVData = ImplGetSVData(); + + if (pSVData->mpWakeCallback && pSVData->mpPollClosure) + pSVData->mpWakeCallback(pSVData->mpPollClosure); + + SvpSalYieldMutex *const pMutex(static_cast(GetYieldMutex())); + std::scoped_lock g(pMutex->m_WakeUpMainMutex); + if (request != SvpRequest::NONE) + pMutex->m_Request = request; + pMutex->m_wakeUpMain = true; + pMutex->m_WakeUpMainCond.notify_one(); +} + +bool SvpSalInstance::CheckTimeout( bool bExecuteTimers ) +{ + bool bRet = false; + if( m_aTimeout.tv_sec ) // timer is started + { + timeval aTimeOfDay; + gettimeofday( &aTimeOfDay, nullptr ); + if( aTimeOfDay >= m_aTimeout ) + { + bRet = true; + if( bExecuteTimers ) + { + // timed out, update timeout + m_aTimeout = aTimeOfDay; + m_aTimeout += m_nTimeoutMS; + + osl::Guard< comphelper::SolarMutex > aGuard( GetYieldMutex() ); + + // notify + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData->maSchedCtx.mpSalTimer ) + pSVData->maSchedCtx.mpSalTimer->CallCallback(); + } + } + } + return bRet; +} + +SalFrame* SvpSalInstance::CreateChildFrame( SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle ) +{ + return new SvpSalFrame( this, nullptr, nStyle ); +} + +SalFrame* SvpSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags 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; +} + +#ifndef IOS + +std::unique_ptr SvpSalInstance::CreateVirtualDevice(SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, + const SystemGraphicsData* pGd) +{ + SvpSalGraphics *pSvpSalGraphics = dynamic_cast(pGraphics); + assert(pSvpSalGraphics); +#ifndef ANDROID + // tdf#127529 normally pPreExistingTarget is null and we are a true virtualdevice drawing to a backing buffer. + // Occasionally, for canvas/slideshow, pPreExistingTarget is pre-provided as a hack to use the vcl drawing + // apis to render onto a preexisting cairo surface. The necessity for that precedes the use of cairo in vcl proper + cairo_surface_t* pPreExistingTarget = pGd ? static_cast(pGd->pSurface) : nullptr; +#else + //ANDROID case + (void)pGd; + cairo_surface_t* pPreExistingTarget = nullptr; +#endif + std::unique_ptr pNew(new SvpSalVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget)); + pNew->SetSize( nDX, nDY ); + return pNew; +} + +cairo_surface_t* get_underlying_cairo_surface(const VirtualDevice& rDevice) +{ + return static_cast(rDevice.mpVirDev.get())->GetSurface(); +} + +#endif + +SalTimer* SvpSalInstance::CreateSalTimer() +{ + return new SvpSalTimer( this ); +} + +SalSystem* SvpSalInstance::CreateSalSystem() +{ + return new SvpSalSystem(); +} + +std::shared_ptr SvpSalInstance::CreateSalBitmap() +{ +#ifdef IOS + return std::make_shared(); +#else + return std::make_shared(); +#endif +} + +void SvpSalInstance::ProcessEvent( SalUserEvent aEvent ) +{ + aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); + if( aEvent.m_nEvent == SalEvent::Resize ) + { + // this would be a good time to post a paint + const SvpSalFrame* pSvpFrame = static_cast( aEvent.m_pFrame); + pSvpFrame->PostPaint(); + } +#ifndef NDEBUG + if (!g_CheckedMutex) + { + assert(dynamic_cast(GetYieldMutex()) != nullptr + && "This SvpSalInstance function requires use of SvpSalYieldMutex"); + g_CheckedMutex = true; + } +#endif + SvpSalYieldMutex *const pMutex(static_cast(GetYieldMutex())); + pMutex->m_NonMainWaitingYieldCond.set(); +} + +SvpSalYieldMutex::SvpSalYieldMutex() +{ +#ifndef IOS + m_FeedbackFDs[0] = m_FeedbackFDs[1] = -1; +#endif +} + +SvpSalYieldMutex::~SvpSalYieldMutex() +{ +} + +void SvpSalYieldMutex::doAcquire(sal_uInt32 const nLockCount) +{ + SvpSalInstance *const pInst = static_cast(GetSalData()->m_pInstance); + if (pInst && pInst->IsMainThread()) + { + if (m_bNoYieldLock) + return; + + do + { + SvpRequest request = SvpRequest::NONE; + { + std::unique_lock g(m_WakeUpMainMutex); + if (m_aMutex.tryToAcquire()) { + // if there's a request, the other thread holds m_aMutex + assert(m_Request == SvpRequest::NONE); + m_wakeUpMain = false; + break; + } + m_WakeUpMainCond.wait(g, [this]() { return m_wakeUpMain; }); + m_wakeUpMain = false; + std::swap(m_Request, request); + } + if (request != SvpRequest::NONE) + { + // nested Yield on behalf of another thread + assert(!m_bNoYieldLock); + m_bNoYieldLock = true; + bool const bEvents = pInst->DoYield(false, request == SvpRequest::MainThreadDispatchAllEvents); + m_bNoYieldLock = false; + write(m_FeedbackFDs[1], &bEvents, sizeof(bool)); + } + } + while (true); + } + else + { + m_aMutex.acquire(); + } + ++m_nCount; + SalYieldMutex::doAcquire(nLockCount - 1); +} + +sal_uInt32 SvpSalYieldMutex::doRelease(bool const bUnlockAll) +{ + SvpSalInstance *const pInst = static_cast(GetSalData()->m_pInstance); + if (pInst && pInst->IsMainThread()) + { + if (m_bNoYieldLock) + return 1; + else + return SalYieldMutex::doRelease(bUnlockAll); + } + sal_uInt32 nCount; + { + // read m_nCount before doRelease + bool const isReleased(bUnlockAll || m_nCount == 1); + nCount = comphelper::SolarMutex::doRelease( bUnlockAll ); + + if (isReleased) + { + if (vcl::lok::isUnipoll()) + { + if (pInst) + pInst->Wakeup(SvpRequest::NONE); + } + else + { + std::scoped_lock g(m_WakeUpMainMutex); + m_wakeUpMain = true; + m_WakeUpMainCond.notify_one(); + } + } + } + return nCount; +} + +bool SvpSalYieldMutex::IsCurrentThread() const +{ + if (GetSalData()->m_pInstance->IsMainThread() && m_bNoYieldLock) + { + return true; + } + else + { + return SalYieldMutex::IsCurrentThread(); + } +} + +bool SvpSalInstance::IsMainThread() const +{ + return osl::Thread::getCurrentIdentifier() == m_MainThread; +} + +void SvpSalInstance::updateMainThread() +{ + if (!IsMainThread()) + { + m_MainThread = osl::Thread::getCurrentIdentifier(); + ImplGetSVData()->mnMainThreadId = osl::Thread::getCurrentIdentifier(); + } +} + +bool SvpSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +{ +#ifndef NDEBUG + if (!g_CheckedMutex) + { + assert(dynamic_cast(GetYieldMutex()) != nullptr + && "This SvpSalInstance function requires use of SvpSalYieldMutex"); + g_CheckedMutex = true; + } +#endif + + // first, process current user events + bool bEvent = DispatchUserEvents(bHandleAllCurrentEvents); + if (!bHandleAllCurrentEvents && bEvent) + return true; + + ImplSVData* pSVData = ImplGetSVData(); + + bool bTimeout = CheckTimeout(); + bool bSkipPoll = bEvent; + if (pSVData->mpPollCallback == nullptr) + bSkipPoll = bEvent || bTimeout; + // else - give the poll-callback visibility into waiting timeouts too. + + SvpSalYieldMutex *const pMutex(static_cast(GetYieldMutex())); + + if (IsMainThread()) + { + // in kit case + if (bWait && !bSkipPoll) + { + sal_Int64 nTimeoutMicroS = 0; + if (m_aTimeout.tv_sec) // Timer is started. + { + timeval Timeout; + // determine remaining timeout. + gettimeofday (&Timeout, nullptr); + if (m_aTimeout > Timeout) + nTimeoutMicroS = ((m_aTimeout.tv_sec - Timeout.tv_sec) * 1000 * 1000 + + (m_aTimeout.tv_usec - Timeout.tv_usec)); + } + else + nTimeoutMicroS = -1; // wait until something happens + + sal_uInt32 nAcquireCount = ReleaseYieldMutexAll(); + + if (pSVData->mpPollCallback) + { + // Poll for events from the LOK client. + if (nTimeoutMicroS < 0) + nTimeoutMicroS = 5000 * 1000; + + // External poll. + if (pSVData->mpPollClosure != nullptr && + pSVData->mpPollCallback(pSVData->mpPollClosure, nTimeoutMicroS) < 0) + pSVData->maAppData.mbAppQuit = true; + } + else + { + std::unique_lock g(pMutex->m_WakeUpMainMutex); + // wait for doRelease() or Wakeup() to set the condition + if (nTimeoutMicroS == -1) + { + pMutex->m_WakeUpMainCond.wait(g, + [pMutex]() { return pMutex->m_wakeUpMain; }); + } + else + { + int nTimeoutMS = nTimeoutMicroS / 1000; + if ( nTimeoutMicroS % 1000 ) + nTimeoutMS += 1; + pMutex->m_WakeUpMainCond.wait_for(g, + std::chrono::milliseconds(nTimeoutMS), + [pMutex]() { return pMutex->m_wakeUpMain; }); + } + // here no need to check m_Request because Acquire will do it + } + AcquireYieldMutex( nAcquireCount ); + } + else if (bSkipPoll) + { + pMutex->m_NonMainWaitingYieldCond.set(); // wake up other threads + } + } + else // !IsMainThread() + { + Wakeup(bHandleAllCurrentEvents + ? SvpRequest::MainThreadDispatchAllEvents + : SvpRequest::MainThreadDispatchOneEvent); + + bool bDidWork(false); + // blocking read (for synchronisation) + auto const nRet = read(pMutex->m_FeedbackFDs[0], &bDidWork, sizeof(bool)); + assert(nRet == 1); (void) nRet; + if (!bDidWork && bWait) + { + // block & release YieldMutex until the main thread does something + pMutex->m_NonMainWaitingYieldCond.reset(); + sal_uInt32 nAcquireCount = ReleaseYieldMutexAll(); + pMutex->m_NonMainWaitingYieldCond.wait(); + AcquireYieldMutex( nAcquireCount ); + } + } + + return bSkipPoll; +} + +bool SvpSalInstance::AnyInput( VclInputFlags nType ) +{ + if( nType & VclInputFlags::TIMER ) + return CheckTimeout( false ); + return false; +} + +OUString SvpSalInstance::GetConnectionIdentifier() +{ + return OUString(); +} + +void SvpSalInstance::StopTimer() +{ + m_aTimeout.tv_sec = 0; + m_aTimeout.tv_usec = 0; + m_nTimeoutMS = 0; +} + +void SvpSalInstance::StartTimer( sal_uInt64 nMS ) +{ + timeval aPrevTimeout (m_aTimeout); + gettimeofday (&m_aTimeout, nullptr); + + m_nTimeoutMS = nMS; + m_aTimeout += m_nTimeoutMS; + + if ((aPrevTimeout > m_aTimeout) || (aPrevTimeout.tv_sec == 0)) + { + // Wakeup from previous timeout (or stopped timer). + Wakeup(); + } +} + +void SvpSalInstance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&) +{ +} + +std::shared_ptr SvpSalInstance::GetBackendCapabilities() +{ + auto pBackendCapabilities = SalInstance::GetBackendCapabilities(); + pBackendCapabilities->mbSupportsBitmap32 = true; + return pBackendCapabilities; +} + +//obviously doesn't actually do anything, it's just a nonfunctional stub + +#if HAVE_FEATURE_UI + +namespace { + +class SvpOpenGLContext : public OpenGLContext +{ + GLWindow m_aGLWin; +private: + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } +}; + +} + +OpenGLContext* SvpSalInstance::CreateOpenGLContext() +{ + return new SvpOpenGLContext; +} + +#else + +class SvpOpenGLContext +{ +}; + +OpenGLContext* SvpSalInstance::CreateOpenGLContext() +{ + return nullptr; +} + + +#endif + +SvpSalTimer::~SvpSalTimer() +{ +} + +void SvpSalTimer::Stop() +{ + m_pInstance->StopTimer(); +} + +void SvpSalTimer::Start( sal_uInt64 nMS ) +{ + m_pInstance->StartTimer( nMS ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpprn.cxx b/vcl/headless/svpprn.cxx new file mode 100644 index 000000000..aa8cd59de --- /dev/null +++ b/vcl/headless/svpprn.cxx @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +using namespace psp; + +/* + * static helpers + */ + +static OUString getPdfDir( const PrinterInfo& rInfo ) +{ + OUString aDir; + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); + if( aToken.startsWith( "pdf=" ) ) + { + sal_Int32 nPos = 0; + aDir = aToken.getToken( 1, '=', nPos ); + if( aDir.isEmpty() ) + aDir = OStringToOUString( OString( getenv( "HOME" ) ), osl_getThreadTextEncoding() ); + break; + } + } + return aDir; +} + +static int PtTo10Mu( int nPoints ) { return static_cast((static_cast(nPoints)*35.27777778)+0.5); } + +static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) +{ + pJobSetup->SetOrientation( rData.m_eOrientation == orientation::Landscape ? Orientation::Landscape : Orientation::Portrait ); + + // copy page size + OUString aPaper; + int width, height; + + rData.m_aContext.getPageSize( aPaper, width, height ); + pJobSetup->SetPaperFormat( PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 )) ); + pJobSetup->SetPaperWidth( 0 ); + pJobSetup->SetPaperHeight( 0 ); + if( pJobSetup->GetPaperFormat() == PAPER_USER ) + { + // transform to 100dth mm + width = PtTo10Mu( width ); + height = PtTo10Mu( height ); + + if( rData.m_eOrientation == psp::orientation::Portrait ) + { + pJobSetup->SetPaperWidth( width ); + pJobSetup->SetPaperHeight( height ); + } + else + { + pJobSetup->SetPaperWidth( height ); + pJobSetup->SetPaperHeight( width ); + } + } + + // copy input slot + const PPDKey* pKey = nullptr; + const PPDValue* pValue = nullptr; + + pJobSetup->SetPaperBin( 0xffff ); + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( "InputSlot" ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + int nPaperBin; + for( nPaperBin = 0; + pValue != pKey->getValue( nPaperBin ) && + nPaperBin < pKey->countValues(); + nPaperBin++ ); + pJobSetup->SetPaperBin( + (nPaperBin == pKey->countValues() + || pValue == pKey->getDefaultValue()) + ? 0xffff : nPaperBin); + } + + // copy duplex + pKey = nullptr; + pValue = nullptr; + + pJobSetup->SetDuplexMode( DuplexMode::Unknown ); + if( rData.m_pParser ) + pKey = rData.m_pParser->getKey( "Duplex" ); + if( pKey ) + pValue = rData.m_aContext.getValue( pKey ); + if( pKey && pValue ) + { + if( pValue->m_aOption.equalsIgnoreAsciiCase( "None" ) || + pValue->m_aOption.startsWithIgnoreAsciiCase( "Simplex" ) + ) + { + pJobSetup->SetDuplexMode( DuplexMode::Off ); + } + else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexNoTumble" ) ) + { + pJobSetup->SetDuplexMode( DuplexMode::LongEdge ); + } + else if( pValue->m_aOption.equalsIgnoreAsciiCase( "DuplexTumble" ) ) + { + pJobSetup->SetDuplexMode( DuplexMode::ShortEdge ); + } + } + + // copy the whole context + if( pJobSetup->GetDriverData() ) + std::free( const_cast(pJobSetup->GetDriverData()) ); + + sal_uInt32 nBytes; + void* pBuffer = nullptr; + if( rData.getStreamBuffer( pBuffer, nBytes ) ) + { + pJobSetup->SetDriverDataLen( nBytes ); + pJobSetup->SetDriverData( static_cast(pBuffer) ); + } + else + { + pJobSetup->SetDriverDataLen( 0 ); + pJobSetup->SetDriverData( nullptr ); + } +} + +// SalInstance + +SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pJobSetup ) +{ + // create and initialize SalInfoPrinter + SvpSalInfoPrinter* pPrinter = new SvpSalInfoPrinter; + + 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->GetDriverData() ) + JobData::constructFromStreamBuffer( pJobSetup->GetDriverData(), + pJobSetup->GetDriverDataLen(), aInfo ); + + pJobSetup->SetSystem( JOBSETUP_SYSTEM_UNIX ); + pJobSetup->SetPrinterName( pQueueInfo->maPrinterName ); + pJobSetup->SetDriver( aInfo.m_aDriverName ); + copyJobDataToJobSetup( pJobSetup, aInfo ); + } + + return pPrinter; +} + +void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + delete pPrinter; +} + +std::unique_ptr SvpSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) +{ + // create and initialize SalPrinter + SvpSalPrinter* pPrinter = new SvpSalPrinter( pInfoPrinter ); + pPrinter->m_aJobData = static_cast(pInfoPrinter)->m_aJobData; + + return std::unique_ptr(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::vector< OUString > aPrinters; + rManager.listPrinters( aPrinters ); + + for (auto const& printer : aPrinters) + { + const PrinterInfo& rInfo( rManager.getPrinterInfo(printer) ); + // create new entry + std::unique_ptr pInfo(new SalPrinterQueueInfo); + pInfo->maPrinterName = printer; + pInfo->maDriver = rInfo.m_aDriverName; + pInfo->maLocation = rInfo.m_aLocation; + pInfo->maComment = rInfo.m_aComment; + + sal_Int32 nIndex = 0; + while( nIndex != -1 ) + { + OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); + if( aToken.startsWith( "pdf=" ) ) + { + pInfo->maLocation = getPdfDir( rInfo ); + break; + } + } + + pList->Add( std::move(pInfo) ); + } +} + +void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) +{ +} + +OUString SvpSalInstance::GetDefaultPrinter() +{ + PrinterInfoManager& rManager( PrinterInfoManager::get() ); + return rManager.getDefaultPrinter(); +} + +void SvpSalInstance::PostPrintersChanged() +{ + SvpSalInstance *pInst = SvpSalInstance::s_pDefaultInstance; + for (auto pSalFrame : pInst->getFrames() ) + pInst->PostEvent( pSalFrame, nullptr, SalEvent::PrinterChanged ); +} + +std::unique_ptr SvpSalInstance::CreatePrintGraphics() +{ + return std::make_unique(); +} + +bool SvpSalInfoPrinter::Setup( weld::Window*, ImplJobSetup* ) +{ + return false; +} + +SvpSalPrinter::SvpSalPrinter( SalInfoPrinter* pInfoPrinter ) + : PspSalPrinter( pInfoPrinter ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx new file mode 100644 index 000000000..e4b625b36 --- /dev/null +++ b/vcl/headless/svptext.cxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void SvpSalGraphics::SetFont(LogicalFontInstance* pIFSD, int nFallbackLevel) +{ + m_aTextRenderImpl.SetFont(pIFSD, nFallbackLevel); +} + +void SvpSalGraphics::GetFontMetric( ImplFontMetricDataRef& xFontMetric, int nFallbackLevel ) +{ + m_aTextRenderImpl.GetFontMetric(xFontMetric, nFallbackLevel); +} + +FontCharMapRef SvpSalGraphics::GetFontCharMap() const +{ + return m_aTextRenderImpl.GetFontCharMap(); +} + +bool SvpSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +{ + return m_aTextRenderImpl.GetFontCapabilities(rFontCapabilities); +} + +void SvpSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) +{ + m_aTextRenderImpl.GetDevFontList(pFontCollection); +} + +void SvpSalGraphics::ClearDevFontCache() +{ + m_aTextRenderImpl.ClearDevFontCache(); +} + +bool SvpSalGraphics::AddTempDevFont( PhysicalFontCollection* pFontCollection, + const OUString& rFileURL, const OUString& rFontName) +{ + return m_aTextRenderImpl.AddTempDevFont(pFontCollection, rFileURL, rFontName); +} + +bool SvpSalGraphics::CreateFontSubset( + const OUString& rToFile, + const PhysicalFontFace* pFont, + const sal_GlyphId* pGlyphIds, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphCount, + FontSubsetInfo& rInfo) +{ + return m_aTextRenderImpl.CreateFontSubset(rToFile, pFont, pGlyphIds, pEncoding, pWidths, nGlyphCount, rInfo); +} + +const void* SvpSalGraphics::GetEmbedFontData(const PhysicalFontFace* pFont, long* pDataLen) +{ + return m_aTextRenderImpl.GetEmbedFontData(pFont, pDataLen); +} + +void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen ) +{ + m_aTextRenderImpl.FreeEmbedFontData(pData, nLen); +} + +void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) +{ + m_aTextRenderImpl.GetGlyphWidths(pFont, bVertical, rWidths, rUnicodeEnc); +} + +std::unique_ptr SvpSalGraphics::GetTextLayout(int nFallbackLevel) +{ + if (utl::ConfigManager::IsFuzzing()) + return nullptr; + return m_aTextRenderImpl.GetTextLayout(nFallbackLevel); +} + +void SvpSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout) +{ + m_aTextRenderImpl.DrawTextLayout(rLayout, *this); +} + +void SvpSalGraphics::SetTextColor( Color nColor ) +{ + m_aTextRenderImpl.SetTextColor(nColor); +} + +#if ENABLE_CAIRO_CANVAS + +SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const +{ + return m_aTextRenderImpl.GetSysFontData(nFallbacklevel); +} + +#endif // ENABLE_CAIRO_CANVAS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx new file mode 100644 index 000000000..70ac5785e --- /dev/null +++ b/vcl/headless/svpvd.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef IOS + +#include +#include +#include +#include + +#include +#include + +#include + +using namespace basegfx; + +SvpSalVirtualDevice::SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget) + : m_eFormat(eFormat) + , m_pRefSurface(pRefSurface) + , m_pSurface(pPreExistingTarget) + , m_bOwnsSurface(!pPreExistingTarget) +{ + cairo_surface_reference(m_pRefSurface); +} + +SvpSalVirtualDevice::~SvpSalVirtualDevice() +{ + if (m_bOwnsSurface) + cairo_surface_destroy(m_pSurface); + cairo_surface_destroy(m_pRefSurface); +} + +SvpSalGraphics* SvpSalVirtualDevice::AddGraphics(SvpSalGraphics* pGraphics) +{ + pGraphics->setSurface(m_pSurface, m_aFrameSize); + m_aGraphics.push_back(pGraphics); + return pGraphics; +} + +SalGraphics* SvpSalVirtualDevice::AcquireGraphics() +{ + return AddGraphics(new SvpSalGraphics()); +} + +void SvpSalVirtualDevice::ReleaseGraphics( SalGraphics* pGraphics ) +{ + m_aGraphics.erase(std::remove(m_aGraphics.begin(), m_aGraphics.end(), dynamic_cast(pGraphics)), m_aGraphics.end()); + delete pGraphics; +} + +bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY ) +{ + return SetSizeUsingBuffer(nNewDX, nNewDY, nullptr); +} + +void SvpSalVirtualDevice::CreateSurface(long nNewDX, long nNewDY, sal_uInt8 *const pBuffer) +{ + if (m_pSurface) + { + cairo_surface_destroy(m_pSurface); + } + + if (m_eFormat == DeviceFormat::BITMASK) + { + m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_ALPHA, + nNewDX, nNewDY); + } + else if (pBuffer) + { + double fXScale, fYScale; + if (comphelper::LibreOfficeKit::isActive()) + { + // Force scaling of the painting + fXScale = fYScale = comphelper::LibreOfficeKit::getDPIScale(); + } + else + { + dl_cairo_surface_get_device_scale(m_pRefSurface, &fXScale, &fYScale); + nNewDX *= fXScale; + nNewDY *= fYScale; + } + + m_pSurface = cairo_image_surface_create_for_data(pBuffer, CAIRO_FORMAT_ARGB32, + nNewDX, nNewDY, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nNewDX)); + + dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale); + } + else + { + m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_COLOR_ALPHA, nNewDX, nNewDY); + } +} + +bool SvpSalVirtualDevice::SetSizeUsingBuffer( long nNewDX, long nNewDY, + sal_uInt8 *const pBuffer) +{ + if (nNewDX == 0) + nNewDX = 1; + if (nNewDY == 0) + nNewDY = 1; + + if (!m_pSurface || m_aFrameSize.getX() != nNewDX || + m_aFrameSize.getY() != nNewDY) + { + m_aFrameSize = basegfx::B2IVector(nNewDX, nNewDY); + + if (m_bOwnsSurface) + CreateSurface(nNewDX, nNewDY, pBuffer); + + assert(m_pSurface); + + // update device in existing graphics + for (auto const& graphic : m_aGraphics) + graphic->setSurface(m_pSurface, m_aFrameSize); + } + return true; +} + +long SvpSalVirtualDevice::GetWidth() const +{ + return m_pSurface ? m_aFrameSize.getX() : 0; +} + +long SvpSalVirtualDevice::GetHeight() const +{ + return m_pSurface ? m_aFrameSize.getY() : 0; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapColorizeFilter.hxx b/vcl/inc/BitmapColorizeFilter.hxx new file mode 100644 index 000000000..93e4d92b2 --- /dev/null +++ b/vcl/inc/BitmapColorizeFilter.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAPCOLORIZEFILTER_HXX +#define INCLUDED_VCL_INC_BITMAPCOLORIZEFILTER_HXX + +#include + +#include + +class BitmapColorizeFilter final : public BitmapFilter +{ +public: + BitmapColorizeFilter(Color aColor) + : maColor(aColor) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) const override; + +private: + Color maColor; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapDisabledImageFilter.hxx b/vcl/inc/BitmapDisabledImageFilter.hxx new file mode 100644 index 000000000..0967cad6b --- /dev/null +++ b/vcl/inc/BitmapDisabledImageFilter.hxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAPDISABLEDIMAGEFILTER_HXX +#define INCLUDED_VCL_INC_BITMAPDISABLEDIMAGEFILTER_HXX + +#include + +class VCL_DLLPUBLIC BitmapDisabledImageFilter final : public BitmapFilter +{ +public: + BitmapDisabledImageFilter() {} + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) const override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapFastScaleFilter.hxx b/vcl/inc/BitmapFastScaleFilter.hxx new file mode 100644 index 000000000..09fbdcaeb --- /dev/null +++ b/vcl/inc/BitmapFastScaleFilter.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef VCL_INC_BITMAPFASTSCALEFILTER_HXX +#define VCL_INC_BITMAPFASTSCALEFILTER_HXX + +#include +#include + +class BitmapFastScaleFilter final : public BitmapFilter +{ +public: + explicit BitmapFastScaleFilter(double fScaleX, double fScaleY) + : mfScaleX(fScaleX) + , mfScaleY(fScaleY) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) const override; + +private: + double mfScaleX; + double mfScaleY; + Size maSize; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapInterpolateScaleFilter.hxx b/vcl/inc/BitmapInterpolateScaleFilter.hxx new file mode 100644 index 000000000..8cbae0601 --- /dev/null +++ b/vcl/inc/BitmapInterpolateScaleFilter.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef VCL_INC_BITMAPINTERPOLATESCALEFILTER_HXX +#define VCL_INC_BITMAPINTERPOLATESCALEFILTER_HXX + +#include +#include + +class BitmapInterpolateScaleFilter final : public BitmapFilter +{ +public: + explicit BitmapInterpolateScaleFilter(double fScaleX, double fScaleY) + : mfScaleX(fScaleX) + , mfScaleY(fScaleY) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmapEx) const override; + +private: + double mfScaleX; + double mfScaleY; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapLightenFilter.hxx b/vcl/inc/BitmapLightenFilter.hxx new file mode 100644 index 000000000..f30e0d5bb --- /dev/null +++ b/vcl/inc/BitmapLightenFilter.hxx @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAPLIGHTENFILTER_HXX +#define INCLUDED_VCL_INC_BITMAPLIGHTENFILTER_HXX + +#include + +class BitmapLightenFilter final : public BitmapFilter +{ +public: + virtual BitmapEx execute(BitmapEx const& rBitmapEx) const override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapScaleConvolutionFilter.hxx b/vcl/inc/BitmapScaleConvolutionFilter.hxx new file mode 100644 index 000000000..9bc1bd45c --- /dev/null +++ b/vcl/inc/BitmapScaleConvolutionFilter.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef VCL_INC_BITMAPSCALECONVOLUTIONFILTER_HXX +#define VCL_INC_BITMAPSCALECONVOLUTIONFILTER_HXX + +#include + +#include "ResampleKernel.hxx" + +namespace vcl +{ +class BitmapScaleConvolutionFilter : public BitmapFilter +{ +protected: + BitmapScaleConvolutionFilter(const double& rScaleX, const double& rScaleY, std::unique_ptr pKernel) + : mxKernel(std::move(pKernel)) + , mrScaleX(rScaleX) + , mrScaleY(rScaleY) + { + } + + virtual BitmapEx execute(BitmapEx const& rBitmap) const override; + +private: + std::unique_ptr mxKernel; + double mrScaleX; + double mrScaleY; +}; + +class VCL_DLLPUBLIC BitmapScaleBilinearFilter final : public BitmapScaleConvolutionFilter +{ +public: + BitmapScaleBilinearFilter(const double& rScaleX, const double& rScaleY) + : BitmapScaleConvolutionFilter(rScaleX, rScaleY, std::make_unique()) + { + } +}; + +class VCL_DLLPUBLIC BitmapScaleBicubicFilter final : public BitmapScaleConvolutionFilter +{ +public: + BitmapScaleBicubicFilter(const double& rScaleX, const double& rScaleY) + : BitmapScaleConvolutionFilter(rScaleX, rScaleY, std::make_unique()) + { + } +}; + +class VCL_DLLPUBLIC BitmapScaleLanczos3Filter final : public BitmapScaleConvolutionFilter +{ +public: + BitmapScaleLanczos3Filter(const double& rScaleX, const double& rScaleY) + : BitmapScaleConvolutionFilter(rScaleX, rScaleY, std::make_unique()) + { + } +}; + +} + +#endif // VCL_INC_BITMAPSCALECONVOLUTIONFILTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapScaleSuperFilter.hxx b/vcl/inc/BitmapScaleSuperFilter.hxx new file mode 100644 index 000000000..47e48eb1a --- /dev/null +++ b/vcl/inc/BitmapScaleSuperFilter.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_BITMAPSCALESUPER_HXX +#define INCLUDED_VCL_INC_BITMAPSCALESUPER_HXX + +#include + +class BitmapScaleSuperFilter final : public BitmapFilter +{ +public: + BitmapScaleSuperFilter(const double& rScaleX, const double& rScaleY); + virtual ~BitmapScaleSuperFilter() override; + + virtual BitmapEx execute(BitmapEx const& rBitmap) const override; + +private: + double mrScaleX; + double mrScaleY; + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/BitmapSymmetryCheck.hxx b/vcl/inc/BitmapSymmetryCheck.hxx new file mode 100644 index 000000000..faf058923 --- /dev/null +++ b/vcl/inc/BitmapSymmetryCheck.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAPSYMMETRYCHECK_HXX +#define INCLUDED_VCL_INC_BITMAPSYMMETRYCHECK_HXX + +#include +#include + +class VCL_DLLPUBLIC BitmapSymmetryCheck final +{ +public: + BitmapSymmetryCheck(); + ~BitmapSymmetryCheck(); + + static bool check(Bitmap& rBitmap); + +private: + static bool checkImpl(BitmapReadAccess const * pReadAccess); +}; + +#endif // INCLUDED_VCL_INC_BITMAPSYMMETRYCHECK_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ControlCacheKey.hxx b/vcl/inc/ControlCacheKey.hxx new file mode 100644 index 000000000..9c8f467ee --- /dev/null +++ b/vcl/inc/ControlCacheKey.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_CONTROLCACHEKEY_HXX +#define INCLUDED_VCL_INC_CONTROLCACHEKEY_HXX + +#include +#include +#include + +class ControlCacheKey +{ +public: + ControlType mnType; + ControlPart mnPart; + ControlState mnState; + Size maSize; + + ControlCacheKey(ControlType nType, ControlPart nPart, ControlState nState, const Size& rSize) + : mnType(nType) + , mnPart(nPart) + , mnState(nState) + , maSize(rSize) + {} + + bool operator==(ControlCacheKey const& aOther) const + { + return mnType == aOther.mnType + && mnPart == aOther.mnPart + && mnState == aOther.mnState + && maSize.Width() == aOther.maSize.Width() + && maSize.Height() == aOther.maSize.Height(); + } + + bool canCacheControl() const + { + switch(mnType) + { + case ControlType::Checkbox: + case ControlType::Radiobutton: + case ControlType::ListNode: + case ControlType::Slider: + case ControlType::Progress: + // FIXME: these guys have complex state hidden in ImplControlValue + // structs which affects rendering, needs to be a and needs to be + // part of the key to our cache. + case ControlType::Spinbox: + case ControlType::SpinButtons: + case ControlType::TabItem: + return false; + + case ControlType::Menubar: + if (mnPart == ControlPart::Entire) + return false; + break; + + default: + break; + } + return true; + } +}; + +struct ControlCacheHashFunction +{ + std::size_t operator()(ControlCacheKey const& aCache) const + { + std::size_t seed = 0; + boost::hash_combine(seed, aCache.mnType); + boost::hash_combine(seed, aCache.mnPart); + boost::hash_combine(seed, aCache.mnState); + boost::hash_combine(seed, aCache.maSize.Width()); + boost::hash_combine(seed, aCache.maSize.Height()); + return seed; + } +}; + +#endif // INCLUDED_VCL_INC_CONTROLCACHEKEY_HXX diff --git a/vcl/inc/FileDefinitionWidgetDraw.hxx b/vcl/inc/FileDefinitionWidgetDraw.hxx new file mode 100644 index 000000000..68f5d3489 --- /dev/null +++ b/vcl/inc/FileDefinitionWidgetDraw.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_FILEDEFINITIONWIDGETDRAW_HXX +#define INCLUDED_VCL_INC_FILEDEFINITIONWIDGETDRAW_HXX + +#include "widgetdraw/WidgetDefinition.hxx" +#include "salgdi.hxx" +#include "WidgetDrawInterface.hxx" + +namespace vcl +{ +class FileDefinitionWidgetDraw final : public vcl::WidgetDrawInterface +{ +private: + SalGraphics& m_rGraphics; + bool m_bIsActive; + + std::shared_ptr m_pWidgetDefinition; + + bool resolveDefinition(ControlType eType, ControlPart ePart, ControlState eState, + const ImplControlValue& rValue, long nX, long nY, long nWidth, + long nHeight); + +public: + FileDefinitionWidgetDraw(SalGraphics& rGraphics); + + bool isActive() const { return m_bIsActive; } + + bool isNativeControlSupported(ControlType eType, ControlPart ePart) override; + + bool hitTestNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, const Point& aPos, + bool& rIsInside) override; + + bool drawNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, ControlState eState, + const ImplControlValue& aValue, const OUString& aCaptions, + const Color& rBackgroundColor) override; + + bool getNativeControlRegion(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, ControlState eState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle& rNativeBoundingRegion, + tools::Rectangle& rNativeContentRegion) override; + + bool updateSettings(AllSettings& rSettings) override; +}; + +} // end vcl namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/IconThemeScanner.hxx b/vcl/inc/IconThemeScanner.hxx new file mode 100644 index 000000000..3cbca74a4 --- /dev/null +++ b/vcl/inc/IconThemeScanner.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_ICONTHEMESCANNER_HXX +#define INCLUDED_VCL_ICONTHEMESCANNER_HXX + +#include + +#include +#include + +#include +#include + +// forward declaration of unit test class. Required for friend relationship. +class IconThemeScannerTest; + +namespace vcl { + +/** This class scans a folder for icon themes and provides the results. + */ +class VCL_DLLPUBLIC IconThemeScanner +{ +public: + /** Factory method to create the object. + * Provide a path to search for IconThemes. + */ + static std::shared_ptr Create(const OUString &path); + + /** This method will return the standard path where icon themes are located. + */ + static OUString + GetStandardIconThemePath(); + + const std::vector& + GetFoundIconThemes() const {return mFoundIconThemes;} + + /** Get the IconThemeInfo for a theme. + * If the theme id is not among the found themes, a std::runtime_error will be thrown. + * Use IconThemeIsInstalled() to check whether it is available. + */ + const IconThemeInfo& GetIconThemeInfo(const OUString& themeId); + + /** Checks whether the theme with the provided name has been found in the + * scanned directory. + */ + bool + IconThemeIsInstalled(const OUString& themeId) const; + +private: + IconThemeScanner(); + + /** Scan a directory for icon themes. + * + * @return + * There are several cases when this method will fail: + * - The directory does not exist + * - There are no files which match the pattern images_xxx.zip + */ + void ScanDirectoryForIconThemes(const OUString &path); + + /** Adds the provided icon theme by path. + */ + bool + AddIconThemeByPath(const OUString &path); + + /** Scans the provided directory for icon themes. + * The returned strings will contain the URLs to the icon themes. + */ + static std::vector + ReadIconThemesFromPath(const OUString& dir); + + /** Check whether a single file is valid */ + static bool + FileIsValidIconTheme(const OUString&); + + std::vector mFoundIconThemes; + + friend class ::IconThemeScannerTest; +}; + +} // end namespace vcl + +#endif // INCLUDED_VCL_ICONTHEMESCANNER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/IconThemeSelector.hxx b/vcl/inc/IconThemeSelector.hxx new file mode 100644 index 000000000..0fcd66d1f --- /dev/null +++ b/vcl/inc/IconThemeSelector.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_ICONTHEMESELECTOR_HXX +#define INCLUDED_VCL_ICONTHEMESELECTOR_HXX + +#include + +#include + +#include + +// forward declaration of unit test class. Required for friend relationship. +class IconThemeSelectorTest; + +namespace vcl { +class IconThemeInfo; + +/** This class helps to choose an icon theme from a list of installed themes. + * + * The following factors influence the selection: + * -# When high contrast mode is enabled, the high contrast icon theme is selected (if it is installed). + * -# When a preferred theme has been set (e.g., in the gnome desktop settings), that theme is selected. + */ +class VCL_DLLPUBLIC IconThemeSelector { +public: + IconThemeSelector(); + + /** Select an icon theme from the list of installed themes. + * + * If high contrast mode has been enabled, the highcontrast theme will be selected (if it is available). + * + * @pre + * @p installedThemes must not be empty + */ + OUString + SelectIconTheme( + const std::vector& installedThemes, + const OUString& theme + ) const; + + /** Select the standard icon theme for a desktop environment from a list of installed themes. + * + * If a preferred theme has been set, this one will take precedence. + * + * The same logic as in SelectIconTheme() will apply. + * + * @pre + * @p installedThemes must not be empty + */ + OUString + SelectIconThemeForDesktopEnvironment( + const std::vector& installedThemes, + const OUString& desktopEnvironment) const; + + void + SetUseHighContrastTheme(bool); + + void + SetPreferredIconTheme(const OUString&, bool bDarkIconTheme); + + bool + operator==(const vcl::IconThemeSelector&) const; + + bool + operator!=(const vcl::IconThemeSelector&) const; + +private: + /** Return the first element of the themes, or the fallback if the vector is empty */ + static OUString + ReturnFallback(const std::vector& installedThemes); + + /** The name of the icon theme which is used as fallback */ + static const OUStringLiteral FALLBACK_ICON_THEME_ID; + + + static OUString + GetIconThemeForDesktopEnvironment(const OUString& desktopEnvironment); + + OUString mPreferredIconTheme; + bool mUseHighContrastTheme; + bool mPreferDarkIconTheme; + + friend class ::IconThemeSelectorTest; +}; + +} /* namespace vcl */ + +#endif // INCLUDED_VCL_ICONTHEMESELECTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/OptionalBox.hxx b/vcl/inc/OptionalBox.hxx new file mode 100644 index 000000000..326fc7536 --- /dev/null +++ b/vcl/inc/OptionalBox.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OPTIONALBOX_HXX +#define INCLUDED_VCL_OPTIONALBOX_HXX + +#include +#include + +class OptionalBox final : public VclHBox, public vcl::IPrioritable +{ +private: + bool m_bInFullView; + +public: + explicit OptionalBox(vcl::Window* pParent); + virtual ~OptionalBox() override; + + void HideContent() override; + void ShowContent() override; + bool IsHidden() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/PhysicalFontCollection.hxx b/vcl/inc/PhysicalFontCollection.hxx new file mode 100644 index 000000000..87b94fe2c --- /dev/null +++ b/vcl/inc/PhysicalFontCollection.hxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PHYSICALFONTCOLLECTION_HXX +#define INCLUDED_VCL_INC_PHYSICALFONTCOLLECTION_HXX + +#include + +#include "fontinstance.hxx" +#include "PhysicalFontFamily.hxx" +#include + +#define MAX_GLYPHFALLBACK 16 + +class ImplDeviceFontSizeList; +class ImplGlyphFallbackFontSubstitution; +class ImplPreMatchFontSubstitution; + + +// TODO: merge with ImplFontCache +// TODO: rename to LogicalFontManager + +class VCL_PLUGIN_PUBLIC PhysicalFontCollection final +{ +public: + explicit PhysicalFontCollection(); + ~PhysicalFontCollection(); + + // fill the list with device font faces + void Add( PhysicalFontFace* ); + void Clear(); + int Count() const { return maPhysicalFontFamilies.size(); } + + // find the device font family + PhysicalFontFamily* FindFontFamily( const OUString& rFontName ) const; + PhysicalFontFamily* FindOrCreateFontFamily( const OUString &rFamilyName ); + PhysicalFontFamily* FindFontFamily( FontSelectPattern& ) const; + PhysicalFontFamily* FindFontFamilyByTokenNames(const OUString& rTokenStr) const; + PhysicalFontFamily* FindFontFamilyByAttributes(ImplFontAttrs nSearchType, FontWeight, FontWidth, + FontItalic, const OUString& rSearchFamily) const; + + // suggest fonts for glyph fallback + PhysicalFontFamily* GetGlyphFallbackFont( FontSelectPattern&, + LogicalFontInstance* pLogicalFont, + OUString& rMissingCodes, int nFallbackLevel ) const; + + // prepare platform specific font substitutions + void SetPreMatchHook( ImplPreMatchFontSubstitution* ); + void SetFallbackHook( ImplGlyphFallbackFontSubstitution* ); + + // misc utilities + std::shared_ptr Clone() const; + std::unique_ptr GetDeviceFontList() const; + std::unique_ptr GetDeviceFontSizeList( const OUString& rFontName ) const; + +private: + mutable bool mbMatchData; // true if matching attributes are initialized + + typedef std::unordered_map> PhysicalFontFamilies; + PhysicalFontFamilies maPhysicalFontFamilies; + + ImplPreMatchFontSubstitution* mpPreMatchHook; // device specific prematch substitution + ImplGlyphFallbackFontSubstitution* mpFallbackHook; // device specific glyph fallback substitution + + mutable std::unique_ptr> mpFallbackList; + mutable int mnFallbackCount; + + void ImplInitMatchData() const; + void ImplInitGenericGlyphFallback() const; + + PhysicalFontFamily* ImplFindFontFamilyBySearchName( const OUString& ) const; + PhysicalFontFamily* ImplFindFontFamilyBySubstFontAttr( const utl::FontNameAttr& ) const; + + PhysicalFontFamily* ImplFindFontFamilyOfDefaultFont() const; + +}; + +#endif // INCLUDED_VCL_INC_PHYSICALFONTCOLLECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/PhysicalFontFace.hxx b/vcl/inc/PhysicalFontFace.hxx new file mode 100644 index 000000000..23af5be91 --- /dev/null +++ b/vcl/inc/PhysicalFontFace.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PHYSICALFONTFACE_HXX +#define INCLUDED_VCL_INC_PHYSICALFONTFACE_HXX + +#include +#include +#include + +#include "fontattributes.hxx" + +class LogicalFontInstance; +struct FontMatchStatus; +class FontSelectPattern; +class PhysicalFontFamily; + +struct FontMatchStatus +{ +public: + int mnFaceMatch; + int mnHeightMatch; + int mnWidthMatch; + const OUString* mpTargetStyleName; +}; + + +// TODO: no more direct access to members +// TODO: get rid of height/width for scalable fonts +// TODO: make cloning cheaper + +/** + * abstract base class for physical font faces + * + * It acts as a factory for its corresponding LogicalFontInstances and + * can be extended to cache device and font instance specific data. + */ +class VCL_PLUGIN_PUBLIC PhysicalFontFace : public FontAttributes, public salhelper::SimpleReferenceObject +{ +public: + virtual rtl::Reference CreateFontInstance(const FontSelectPattern&) const = 0; + + int GetHeight() const { return mnHeight; } + int GetWidth() const { return mnWidth; } + virtual sal_IntPtr GetFontId() const = 0; + + bool IsBetterMatch( const FontSelectPattern&, FontMatchStatus& ) const; + sal_Int32 CompareWithSize( const PhysicalFontFace& ) const; + sal_Int32 CompareIgnoreSize( const PhysicalFontFace& ) const; + +protected: + explicit PhysicalFontFace(const FontAttributes&); + void SetBitmapSize( int nW, int nH ) { mnWidth=nW; mnHeight=nH; } + + long mnWidth; // Width (in pixels) + long mnHeight; // Height (in pixels) +}; + +#endif // INCLUDED_VCL_INC_PHYSICALFONTFACE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/vcl/inc/PhysicalFontFamily.hxx b/vcl/inc/PhysicalFontFamily.hxx new file mode 100644 index 000000000..b8468a6e4 --- /dev/null +++ b/vcl/inc/PhysicalFontFamily.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PHYSICALFONTFAMILY_HXX +#define INCLUDED_VCL_INC_PHYSICALFONTFAMILY_HXX + +#include +#include + +#include + +#include + +#include "PhysicalFontFace.hxx" + +class ImplDeviceFontList; +class PhysicalFontFace; +class PhysicalFontCollection; + +// flags for mnTypeFaces member +enum class FontTypeFaces { + NONE = 0x00, + Scalable = 0x01, + Symbol = 0x02, + NoneSymbol = 0x04, + Light = 0x08, + Bold = 0x10, + Normal = 0x20, + NoneItalic = 0x40, + Italic = 0x80 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +class VCL_PLUGIN_PUBLIC PhysicalFontFamily +{ +public: + PhysicalFontFamily( const OUString& rSearchName ); + ~PhysicalFontFamily(); + + const OUString& GetFamilyName() const { return maFamilyName; } + const OUString& GetSearchName() const { return maSearchName; } + const OUString& GetAliasNames() const { return maMapNames; } + int GetMinQuality() const { return mnMinQuality; } + FontTypeFaces GetTypeFaces() const { return mnTypeFaces; } + void GetFontHeights( std::set& rHeights ) const; + + const OUString& GetMatchFamilyName() const { return maMatchFamilyName; } + ImplFontAttrs GetMatchType() const { return mnMatchType ; } + FontWeight GetMatchWeight() const { return meMatchWeight ; } + FontWidth GetMatchWidth() const { return meMatchWidth ; } + void InitMatchData( const utl::FontSubstConfiguration&, + const OUString& rSearchName ); + + void AddFontFace( PhysicalFontFace* ); + + PhysicalFontFace* FindBestFontFace( const FontSelectPattern& rFSD ) const; + + void UpdateDevFontList( ImplDeviceFontList& ) const; + void UpdateCloneFontList(PhysicalFontCollection&) const; + +static void CalcType( ImplFontAttrs& rType, FontWeight& rWeight, FontWidth& rWidth, + FontFamily eFamily, const utl::FontNameAttr* pFontAttr ); + +private: + std::vector< rtl::Reference > maFontFaces; + + OUString maFamilyName; // original font family name + OUString maSearchName; // normalized font family name + OUString maMapNames; // fontname aliases + FontTypeFaces mnTypeFaces; // Typeface Flags + FontFamily meFamily; + FontPitch mePitch; + int mnMinQuality; // quality of the worst font face + + ImplFontAttrs mnMatchType; // MATCH - Type + OUString maMatchFamilyName; // MATCH - FamilyName + FontWeight meMatchWeight; // MATCH - Weight + FontWidth meMatchWidth; // MATCH - Width +}; + +#endif // INCLUDED_VCL_INC_PHYSICALFONTFAMILY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ResampleKernel.hxx b/vcl/inc/ResampleKernel.hxx new file mode 100644 index 000000000..ca54213f5 --- /dev/null +++ b/vcl/inc/ResampleKernel.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_RESAMPLEKERNEL_HXX +#define INCLUDED_VCL_RESAMPLEKERNEL_HXX + +#include + +namespace vcl { + +// Resample kernels + +class Kernel +{ +public: + Kernel() {} + virtual ~Kernel() {} + + virtual double GetWidth() const = 0; + virtual double Calculate( double x ) const = 0; +}; + +class Lanczos3Kernel final : public Kernel +{ +public: + Lanczos3Kernel() : Kernel () {} + + virtual double GetWidth() const override { return 3.0; } + virtual double Calculate (double x) const override + { + return (-3.0 <= x && x < 3.0) ? SincFilter(x) * SincFilter( x / 3.0 ) : 0.0; + } + + static double SincFilter(double x) + { + if (x == 0.0) + { + return 1.0; + } + x = x * M_PI; + return boost::math::sinc_pi(x, SincPolicy()); + } + +private: + typedef boost::math::policies::policy< + boost::math::policies::promote_double > SincPolicy; +}; + +class BicubicKernel final : public Kernel +{ +public: + BicubicKernel() : Kernel () {} + +private: + virtual double GetWidth() const override { return 2.0; } + virtual double Calculate (double x) const override + { + if (x < 0.0) + { + x = -x; + } + + if (x <= 1.0) + { + return (1.5 * x - 2.5) * x * x + 1.0; + } + else if (x < 2.0) + { + return ((-0.5 * x + 2.5) * x - 4) * x + 2; + } + return 0.0; + } +}; + +class BilinearKernel final : public Kernel +{ +public: + BilinearKernel() : Kernel () {} + +private: + virtual double GetWidth() const override { return 1.0; } + virtual double Calculate (double x) const override + { + if (x < 0.0) + { + x = -x; + } + if (x < 1.0) + { + return 1.0-x; + } + return 0.0; + } +}; + +} // namespace vcl + +#endif // INCLUDED_VCL_RESAMPLEKERNEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/SalGradient.hxx b/vcl/inc/SalGradient.hxx new file mode 100644 index 000000000..1b4a47f9a --- /dev/null +++ b/vcl/inc/SalGradient.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SALGRADIENT_HXX +#define INCLUDED_VCL_INC_SALGRADIENT_HXX + +#include + +struct SalGradientStop +{ + Color maColor; + float mfOffset; + + SalGradientStop(Color const& rColor, float fOffset) + : maColor(rColor) + , mfOffset(fOffset) + { + } +}; + +struct SalGradient +{ + basegfx::B2DPoint maPoint1; + basegfx::B2DPoint maPoint2; + std::vector maStops; +}; + +#endif // INCLUDED_VCL_INC_SALGRADIENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/TypeSerializer.hxx b/vcl/inc/TypeSerializer.hxx new file mode 100644 index 000000000..060876593 --- /dev/null +++ b/vcl/inc/TypeSerializer.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_TYPESERIALIZER_HXX +#define INCLUDED_VCL_INC_TYPESERIALIZER_HXX + +#include +#include +#include +#include +#include + +constexpr sal_uInt32 createMagic(char char1, char char2, char char3, char char4) +{ + return (static_cast(char1) << 24) | (static_cast(char2) << 16) + | (static_cast(char3) << 8) | (static_cast(char4) << 0); +} + +class VCL_DLLPUBLIC TypeSerializer : public tools::GenericTypeSerializer +{ +public: + TypeSerializer(SvStream& rStream); + + void readGradient(Gradient& rGradient); + void writeGradient(const Gradient& rGradient); + + void readGfxLink(GfxLink& rGfxLink); + void writeGfxLink(const GfxLink& rGfxLink); + + void readGraphic(Graphic& rGraphic); + void writeGraphic(const Graphic& rGraphic); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/WidgetDrawInterface.hxx b/vcl/inc/WidgetDrawInterface.hxx new file mode 100644 index 000000000..78d5d7625 --- /dev/null +++ b/vcl/inc/WidgetDrawInterface.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_WIDGETDRAWINTERFACE_HXX +#define INCLUDED_VCL_INC_WIDGETDRAWINTERFACE_HXX + +#include +#include +#include + +namespace vcl +{ +class VCL_PLUGIN_PUBLIC WidgetDrawInterface +{ +public: + virtual ~WidgetDrawInterface() COVERITY_NOEXCEPT_FALSE {} + + /** + * Query the platform layer for native control support. + * + * @param [in] eType The widget type. + * @param [in] ePart The part of the widget. + * @return true if the platform supports native drawing of the widget type defined by part. + */ + virtual inline bool isNativeControlSupported(ControlType eType, ControlPart ePart); + + /** + * Query if a position is inside the native widget part. + * + * Mainly used for scrollbars. + * + * @param [in] eType The widget type. + * @param [in] ePart The part of the widget. + * @param [in] rBoundingControlRegion The bounding Rectangle of + the complete control in VCL frame coordinates. + * @param [in] aPos The position to check the hit. + * @param [out] rIsInside true, if \a aPos was inside the native widget. + * @return true, if the query was successful. + */ + virtual inline bool hitTestNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, + const Point& aPos, bool& rIsInside); + + /** + * Draw the requested control. + * + * @param [in] eType The widget type. + * @param [in] ePart The part of the widget. + * @param [in] rBoundingControlRegion The bounding rectangle of + * the complete control in VCL frame coordinates. + * @param [in] eState The general state of the control (enabled, focused, etc.). + * @param [in] aValue Addition control specific information. + * @param [in] aCaption A caption or title string (like button text etc.). + * @param [in] rBackgroundColor Background color for the control (may be COL_AUTO) + * @return true, if the control could be drawn. + */ + virtual inline bool drawNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, + ControlState eState, const ImplControlValue& aValue, + const OUString& aCaptions, const Color& rBackgroundColor); + + /** + * Get the native control regions for the control part. + * + * If the return value is true, \a rNativeBoundingRegion contains + * the true bounding region covered by the control including any + * adornment, while \a rNativeContentRegion contains the area + * within the control that can be safely drawn into without drawing over + * the borders of the control. + * + * @param [in] eType Type of the widget. + * @param [in] ePart Specification of the widget's part if it consists of more than one. + * @param [in] rBoundingControlRegion The bounding region of the control in VCL frame coordinates. + * @param [in] eState The general state of the control (enabled, focused, etc.). + * @param [in] aValue Addition control specific information. + * @param [in] aCaption A caption or title string (like button text etc.). + * @param [out] rNativeBoundingRegion The region covered by the control including any adornment. + * @param [out] rNativeContentRegion The region within the control that can be safely drawn into. + * @return true, if the regions are filled. + */ + virtual inline bool getNativeControlRegion(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, + ControlState eState, const ImplControlValue& aValue, + const OUString& aCaption, + tools::Rectangle& rNativeBoundingRegion, + tools::Rectangle& rNativeContentRegion); + + virtual inline bool updateSettings(AllSettings& rSettings); +}; + +bool WidgetDrawInterface::isNativeControlSupported(ControlType, ControlPart) { return false; } + +bool WidgetDrawInterface::hitTestNativeControl(ControlType, ControlPart, const tools::Rectangle&, + const Point&, bool&) +{ + return false; +} + +bool WidgetDrawInterface::drawNativeControl(ControlType, ControlPart, const tools::Rectangle&, + ControlState, const ImplControlValue&, const OUString&, + const Color& /*rBackgroundColor*/) +{ + return false; +} + +bool WidgetDrawInterface::getNativeControlRegion(ControlType, ControlPart, const tools::Rectangle&, + ControlState, const ImplControlValue&, + const OUString&, tools::Rectangle&, + tools::Rectangle&) +{ + return false; +} + +bool WidgetDrawInterface::updateSettings(AllSettings&) { return false; } +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/WidgetThemeLibrary.hxx b/vcl/inc/WidgetThemeLibrary.hxx new file mode 100644 index 000000000..ace74a49a --- /dev/null +++ b/vcl/inc/WidgetThemeLibrary.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_WIDGETTHEME_HXX +#define INCLUDED_VCL_INC_WIDGETTHEME_HXX + +#include + +namespace vcl +{ +struct WidgetDrawStyle +{ + uint32_t nSize; + uint32_t maFaceColor; + uint32_t maCheckedColor; + uint32_t maLightColor; + uint32_t maLightBorderColor; + uint32_t maShadowColor; + uint32_t maDarkShadowColor; + uint32_t maDefaultButtonTextColor; + uint32_t maButtonTextColor; + uint32_t maDefaultActionButtonTextColor; + uint32_t maActionButtonTextColor; + uint32_t maFlatButtonTextColor; + uint32_t maDefaultButtonRolloverTextColor; + uint32_t maButtonRolloverTextColor; + uint32_t maDefaultActionButtonRolloverTextColor; + uint32_t maActionButtonRolloverTextColor; + uint32_t maFlatButtonRolloverTextColor; + uint32_t maDefaultButtonPressedRolloverTextColor; + uint32_t maButtonPressedRolloverTextColor; + uint32_t maDefaultActionButtonPressedRolloverTextColor; + uint32_t maActionButtonPressedRolloverTextColor; + uint32_t maFlatButtonPressedRolloverTextColor; + uint32_t maRadioCheckTextColor; + uint32_t maGroupTextColor; + uint32_t maLabelTextColor; + uint32_t maWindowColor; + uint32_t maWindowTextColor; + uint32_t maDialogColor; + uint32_t maDialogTextColor; + uint32_t maWorkspaceColor; + uint32_t maMonoColor; + uint32_t maFieldColor; + uint32_t maFieldTextColor; + uint32_t maFieldRolloverTextColor; + uint32_t maActiveColor; + uint32_t maActiveTextColor; + uint32_t maActiveBorderColor; + uint32_t maDeactiveColor; + uint32_t maDeactiveTextColor; + uint32_t maDeactiveBorderColor; + uint32_t maMenuColor; + uint32_t maMenuBarColor; + uint32_t maMenuBarRolloverColor; + uint32_t maMenuBorderColor; + uint32_t maMenuTextColor; + uint32_t maMenuBarTextColor; + uint32_t maMenuBarRolloverTextColor; + uint32_t maMenuBarHighlightTextColor; + uint32_t maMenuHighlightColor; + uint32_t maMenuHighlightTextColor; + uint32_t maHighlightColor; + uint32_t maHighlightTextColor; + uint32_t maActiveTabColor; + uint32_t maInactiveTabColor; + uint32_t maTabTextColor; + uint32_t maTabRolloverTextColor; + uint32_t maTabHighlightTextColor; + uint32_t maDisableColor; + uint32_t maHelpColor; + uint32_t maHelpTextColor; + uint32_t maLinkColor; + uint32_t maVisitedLinkColor; + uint32_t maToolTextColor; + uint32_t maFontColor; +}; + +struct ControlDrawParameters +{ + typedef struct _cairo cairo_t; + ControlDrawParameters(cairo_t* i_pCairo, ControlPart i_ePart, ControlState i_eState) + : nSize(sizeof(ControlDrawParameters)) + , pCairo(i_pCairo) + , ePart(i_ePart) + , eState(i_eState) + , eButtonValue(ButtonValue::DontKnow) + , bIsAction(false) + , nValue(0) + { + } + + uint32_t nSize; + cairo_t* pCairo; + ControlPart ePart; + ControlState eState; + ButtonValue eButtonValue; + bool bIsAction; + int64_t nValue; +}; + +typedef struct WidgetThemeLibrary_t WidgetThemeLibrary; + +typedef struct _rectangle +{ + long x, y; + long width, height; +} rectangle_t; + +struct WidgetThemeLibrary_t +{ + uint32_t nSize; + + bool (*isNativeControlSupported)(ControlType eType, ControlPart ePart); + bool (*getRegion)(ControlType eType, ControlPart ePart, ControlState eState, + const rectangle_t& rBoundingControlRegion, rectangle_t& rNativeBoundingRegion, + rectangle_t& rNativeContentRegion); + + bool (*drawPushButton)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawRadiobutton)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawCheckbox)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawCombobox)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawEditbox)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawScrollbar)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawSpinButtons)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawSpinbox)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawTabItem)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawTabPane)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawTabHeader)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawTabBody)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawSlider)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawFixedline)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawToolbar)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawProgress)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawWindowsBackground)(ControlDrawParameters const& rParameters, long nWidth, + long nHeight); + bool (*drawListbox)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawFrame)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawListNode)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawListNet)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + bool (*drawListHeader)(ControlDrawParameters const& rParameters, long nWidth, long nHeight); + + bool (*updateSettings)(WidgetDrawStyle& rStyle); +}; + +extern "C" vcl::WidgetThemeLibrary* CreateWidgetThemeLibrary(); + +} // end vcl namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/WidgetThemeLibraryTypes.hxx b/vcl/inc/WidgetThemeLibraryTypes.hxx new file mode 100644 index 000000000..b3270bf23 --- /dev/null +++ b/vcl/inc/WidgetThemeLibraryTypes.hxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_WIDGETTHEMETYPES_HXX +#define INCLUDED_VCL_INC_WIDGETTHEMETYPES_HXX + +#include + +/** + * These types are all based on the supported variants + * vcl/salnativewidgets.hxx and must be kept in-sync. + **/ + +/* Control Types: + * + * Specify the overall, whole control + * type (as opposed to parts of the + * control if it were composite). + */ + +enum class ControlType { +// for use in general purpose ImplControlValue + Generic = 0, +// Normal PushButton/Command Button + Pushbutton = 1, +// Normal single radio button + Radiobutton = 2, +// Normal single checkbox + Checkbox = 10, +// Combobox, i.e. a ListBox +// that allows data entry by user + Combobox = 20, +// Control that allows text entry + Editbox = 30, +// Control that allows text entry, but without the usual border +// Has to be handled separately, because this one cannot handle +// ControlPart::HasBackgroundTexture, which is drawn in the edit box'es +// border window. + EditboxNoBorder = 31, +// Control that allows text entry +// ( some systems distinguish between single and multi line edit boxes ) + MultilineEditbox = 32, +// Control that pops up a menu, +// but does NOT allow data entry + Listbox = 35, +// An edit field together with two little +// buttons on the side (aka spin field) + Spinbox = 40, +// Two standalone spin buttons +// without an edit field + SpinButtons = 45, +// A single tab + TabItem = 50, +// The border around a tab area, +// but without the tabs themselves. +// May have a gap at the top for +// the active tab + TabPane = 55, +// The background to the tab area + TabHeader = 56, +// Background of a Tab Pane + TabBody = 57, +// Normal scrollbar, including +// all parts like slider, buttons + Scrollbar = 60, + Slider = 65, +// A separator line + Fixedline = 80, +// A toolbar control with buttons and a grip + Toolbar = 100, +// The menubar + Menubar = 120, +// popup menu + MenuPopup = 121, + 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/) + IntroProgress = 132, +// tool tips + Tooltip = 140, +// to draw the implemented theme + WindowBackground = 150, +//to draw border of frames natively + Frame = 160, +// for nodes in listviews +// used in svtools/source/contnr/svtreebx.cxx + ListNode = 170, +// nets between elements of listviews +// with nodes + ListNet = 171, +// for list headers + ListHeader = 172, +}; + + +/* Control Parts: + * + * Uniquely identify a part of a control, + * for example the slider of a scroll bar. + */ + +enum class ControlPart +{ + NONE = 0, + Entire = 1, + ListboxWindow = 5, // the static listbox window containing the list + Button = 100, + ButtonUp = 101, + ButtonDown = 102, // Also for ComboBoxes/ListBoxes + ButtonLeft = 103, + ButtonRight = 104, + AllButtons = 105, + SeparatorHorz = 106, + SeparatorVert = 107, + TrackHorzLeft = 200, + TrackVertUpper = 201, + TrackHorzRight = 202, + TrackVertLower = 203, + TrackHorzArea = 204, + TrackVertArea = 205, + Arrow = 220, + ThumbHorz = 210, // Also used as toolbar grip + ThumbVert = 211, // Also used as toolbar grip + MenuItem = 250, + MenuItemCheckMark = 251, + MenuItemRadioMark = 252, + Separator = 253, + SubmenuArrow = 254, + +/* #i77549# + HACK: for scrollbars in case of thumb rect, page up and page down rect we + abuse the HitTestNativeScrollbar 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 + HitTestNativeScrollbar 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 HitTestNativeScrollbar on ControlPart::ThumbHorz, ControlPart::ThumbVert, + ControlPart::TrackHorzLeft, ControlPart::TrackHorzRight, ControlPart::TrackVertUpper, ControlPart::TrackVertLower + do not use the control rectangle as region but the actual 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 ControlPart::ButtonDown as + well. +*/ + SubEdit = 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. + DrawBackgroundHorz = 1000, + DrawBackgroundVert = 1001, + +// GTK+ also draws tabs right->left since there is a +// hardcoded 2 pixel overlap between adjacent tabs + TabsDrawRtl = 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 + HasBackgroundTexture = 4000, + +// For scrollbars that have 3 buttons (most KDE themes) + HasThreeButtons = 5000, + + BackgroundWindow = 6000, + BackgroundDialog = 6001, + +//to draw natively the border of frames + Border = 7000, + +//to draw natively the focus rects + Focus = 8000 +}; + +/* 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. + */ +enum class ControlState { + NONE = 0, + ENABLED = 0x0001, + FOCUSED = 0x0002, + PRESSED = 0x0004, + ROLLOVER = 0x0008, + DEFAULT = 0x0020, + SELECTED = 0x0040, + DOUBLEBUFFERING = 0x4000, ///< Set when the control is painted using double-buffering via VirtualDevice. + CACHING_ALLOWED = 0x8000, ///< Set when the control is completely visible (i.e. not clipped). +}; + +template<> struct o3tl::typed_flags: o3tl::is_typed_flags {}; + +/* ButtonValue: + * + * Identifies the tri-state value options + * that buttons allow + */ + +enum class ButtonValue { + DontKnow, + On, + Off, + Mixed +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/accel.h b/vcl/inc/accel.h new file mode 100644 index 000000000..0c27a5411 --- /dev/null +++ b/vcl/inc/accel.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_ACCEL_H +#define INCLUDED_VCL_INC_ACCEL_H + +#include + +class Accelerator; + +class ImplAccelEntry +{ +public: + sal_uInt16 mnId; + vcl::KeyCode maKeyCode; + Accelerator* mpAccel; + Accelerator* mpAutoAccel; + bool mbEnabled; +}; + +bool ImplGetKeyCode( KeyFuncType eFunc, sal_uInt16& rCode1, sal_uInt16& rCode2, sal_uInt16& rCode3, sal_uInt16& rCode4 ); + +#endif // INCLUDED_VCL_INC_ACCEL_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/accmgr.hxx b/vcl/inc/accmgr.hxx new file mode 100644 index 000000000..1e57ed44d --- /dev/null +++ b/vcl/inc/accmgr.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_ACCMGR_HXX +#define INCLUDED_VCL_INC_ACCMGR_HXX + +#include +#include + +#include + +class Accelerator; + +class ImplAccelManager +{ +private: + std::unique_ptr> mpAccelList; + std::unique_ptr> mpSequenceList; + +public: + ImplAccelManager() + { + } + ~ImplAccelManager(); + + bool InsertAccel( Accelerator* pAccel ); + void RemoveAccel( Accelerator const * pAccel ); + + void EndSequence(); + void FlushAccel() { EndSequence(); } + + bool IsAccelKey( const vcl::KeyCode& rKeyCode ); +}; + +#endif // INCLUDED_VCL_INC_ACCMGR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/android/androidinst.hxx b/vcl/inc/android/androidinst.hxx new file mode 100644 index 000000000..526174b14 --- /dev/null +++ b/vcl/inc/android/androidinst.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_ANDROID_ANDROIDINST_HXX +#define INCLUDED_VCL_INC_ANDROID_ANDROIDINST_HXX + +#include +#include +#include +#include +#include + +class AndroidSalFrame; +class AndroidSalInstance : public SvpSalInstance +{ + // This JNIEnv is valid only in the thread where this + // AndroidSalInstance object is created, which is the "LO" thread + // in which soffice_main() runs + JNIEnv *m_pJNIEnv; + +public: + AndroidSalInstance( std::unique_ptr pMutex ); + virtual ~AndroidSalInstance(); + static AndroidSalInstance *getInstance(); + + virtual SalSystem* CreateSalSystem(); + + // frame management + void GetWorkArea( tools::Rectangle& rRect ); + SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ); + SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ); + + // mainloop pieces + virtual bool AnyInput( VclInputFlags nType ); + + virtual void updateMainThread(); + virtual void releaseMainThread(); +}; + +#endif // INCLUDED_VCL_INC_ANDROID_ANDROIDINST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/android/svsys.h b/vcl/inc/android/svsys.h new file mode 100644 index 000000000..6939e5066 --- /dev/null +++ b/vcl/inc/android/svsys.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_ANDROID_SVSYS_H +#define INCLUDED_VCL_INC_ANDROID_SVSYS_H + +// ? + +#endif // INCLUDED_VCL_INC_ANDROID_SVSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/backend/BackendCapabilities.hxx b/vcl/inc/backend/BackendCapabilities.hxx new file mode 100644 index 000000000..89879ee49 --- /dev/null +++ b/vcl/inc/backend/BackendCapabilities.hxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX +#define INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX + +namespace vcl +{ +struct BackendCapabilities +{ + bool mbSupportsBitmap32; + BackendCapabilities() + : mbSupportsBitmap32(false) + { + } +}; +} + +#endif // INCLUDED_VCL_INC_BACKENDCAPABILITIES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/bitmap/Octree.hxx b/vcl/inc/bitmap/Octree.hxx new file mode 100644 index 000000000..f1d6e2a58 --- /dev/null +++ b/vcl/inc/bitmap/Octree.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OCTREE_HXX +#define INCLUDED_VCL_INC_OCTREE_HXX + +#include +#include + +struct OctreeNode +{ + sal_uLong nCount = 0; + sal_uLong nRed = 0; + sal_uLong nGreen = 0; + sal_uLong nBlue = 0; + std::unique_ptr pChild[8]; + OctreeNode* pNext = nullptr; + sal_uInt16 nPalIndex = 0; + bool bLeaf = false; +}; + +class BitmapReadAccess; + +class VCL_PLUGIN_PUBLIC Octree +{ +private: + void CreatePalette(OctreeNode* pNode); + void GetPalIndex(const OctreeNode* pNode); + + SAL_DLLPRIVATE void add(std::unique_ptr& rpNode); + SAL_DLLPRIVATE void reduce(); + + BitmapPalette maPalette; + sal_uLong mnLeafCount; + sal_uLong mnLevel; + std::unique_ptr pTree; + std::vector mpReduce; + BitmapColor const* mpColor; + sal_uInt16 mnPalIndex; + +public: + Octree(const BitmapReadAccess& rReadAcc, sal_uLong nColors); + ~Octree(); + + const BitmapPalette& GetPalette(); + sal_uInt16 GetBestPaletteIndex(const BitmapColor& rColor); +}; + +class InverseColorMap +{ +private: + std::vector mpBuffer; + std::vector mpMap; + + void ImplCreateBuffers(); + +public: + explicit InverseColorMap(const BitmapPalette& rPal); + ~InverseColorMap(); + + sal_uInt16 GetBestPaletteIndex(const BitmapColor& rColor); +}; + +#endif // INCLUDED_VCL_INC_OCTREE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/bitmap/ScanlineTools.hxx b/vcl/inc/bitmap/ScanlineTools.hxx new file mode 100644 index 000000000..9528f4809 --- /dev/null +++ b/vcl/inc/bitmap/ScanlineTools.hxx @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAP_SCANLINETOOLS_HXX +#define INCLUDED_VCL_INC_BITMAP_SCANLINETOOLS_HXX + +#include +#include + +namespace vcl::bitmap +{ +class ScanlineTransformer +{ +public: + virtual void startLine(sal_uInt8* pLine) = 0; + virtual void skipPixel(sal_uInt32 nPixel) = 0; + virtual Color readPixel() = 0; + virtual void writePixel(Color nColor) = 0; + + virtual ~ScanlineTransformer() = default; +}; + +class ScanlineTransformer_ARGB final : public ScanlineTransformer +{ +private: + sal_uInt8* pData; + +public: + virtual void startLine(sal_uInt8* pLine) override { pData = pLine; } + + virtual void skipPixel(sal_uInt32 nPixel) override { pData += nPixel << 2; } + + virtual Color readPixel() override + { + const Color aColor(pData[4], pData[1], pData[2], pData[3]); + pData += 4; + return aColor; + } + + virtual void writePixel(Color nColor) override + { + *pData++ = nColor.GetTransparency(); + *pData++ = nColor.GetRed(); + *pData++ = nColor.GetGreen(); + *pData++ = nColor.GetBlue(); + } +}; + +class ScanlineTransformer_BGR final : public ScanlineTransformer +{ +private: + sal_uInt8* pData; + +public: + virtual void startLine(sal_uInt8* pLine) override { pData = pLine; } + + virtual void skipPixel(sal_uInt32 nPixel) override { pData += (nPixel << 1) + nPixel; } + + virtual Color readPixel() override + { + const Color aColor(pData[2], pData[1], pData[0]); + pData += 3; + return aColor; + } + + virtual void writePixel(Color nColor) override + { + *pData++ = nColor.GetBlue(); + *pData++ = nColor.GetGreen(); + *pData++ = nColor.GetRed(); + } +}; + +class ScanlineTransformer_8BitPalette final : public ScanlineTransformer +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + +public: + explicit ScanlineTransformer_8BitPalette(const BitmapPalette& rPalette) + : pData(nullptr) + , mrPalette(rPalette) + { + } + + virtual void startLine(sal_uInt8* pLine) override { pData = pLine; } + + virtual void skipPixel(sal_uInt32 nPixel) override { pData += nPixel; } + + virtual Color readPixel() override + { + const sal_uInt8 nIndex(*pData++); + if (nIndex < mrPalette.GetEntryCount()) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + + virtual void writePixel(Color nColor) override + { + *pData++ = static_cast(mrPalette.GetBestIndex(nColor)); + } +}; + +class ScanlineTransformer_4BitPalette final : public ScanlineTransformer +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + sal_uInt32 mnX; + sal_uInt32 mnShift; + +public: + explicit ScanlineTransformer_4BitPalette(const BitmapPalette& rPalette) + : pData(nullptr) + , mrPalette(rPalette) + , mnX(0) + , mnShift(0) + { + } + + virtual void skipPixel(sal_uInt32 nPixel) override + { + mnX += nPixel; + if (nPixel & 1) // is nPixel an odd number + mnShift ^= 4; + } + + virtual void startLine(sal_uInt8* pLine) override + { + pData = pLine; + mnX = 0; + mnShift = 4; + } + + virtual Color readPixel() override + { + const sal_uInt32 nDataIndex = mnX / 2; + const sal_uInt8 nIndex((pData[nDataIndex] >> mnShift) & 0x0f); + mnX++; + mnShift ^= 4; + + if (nIndex < mrPalette.GetEntryCount()) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + + virtual void writePixel(Color nColor) override + { + const sal_uInt32 nDataIndex = mnX / 2; + const sal_uInt8 nColorIndex = mrPalette.GetBestIndex(nColor); + pData[nDataIndex] |= (nColorIndex & 0x0f) << mnShift; + mnX++; + mnShift ^= 4; + } +}; + +class ScanlineTransformer_1BitPalette final : public ScanlineTransformer +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + sal_uInt32 mnX; + +public: + explicit ScanlineTransformer_1BitPalette(const BitmapPalette& rPalette) + : pData(nullptr) + , mrPalette(rPalette) + , mnX(0) + { + } + + virtual void skipPixel(sal_uInt32 nPixel) override { mnX += nPixel; } + + virtual void startLine(sal_uInt8* pLine) override + { + pData = pLine; + mnX = 0; + } + + virtual Color readPixel() override + { + const sal_uInt8 nIndex((pData[mnX >> 3] >> (7 - (mnX & 7))) & 1); + mnX++; + + if (nIndex < mrPalette.GetEntryCount()) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + + virtual void writePixel(Color nColor) override + { + if (mrPalette.GetBestIndex(nColor) & 1) + pData[mnX >> 3] |= 1 << (7 - (mnX & 7)); + else + pData[mnX >> 3] &= ~(1 << (7 - (mnX & 7))); + mnX++; + } +}; + +std::unique_ptr getScanlineTransformer(sal_uInt16 nBits, + const BitmapPalette& rPalette) +{ + switch (nBits) + { + case 1: + return std::make_unique(rPalette); + case 4: + return std::make_unique(rPalette); + case 8: + return std::make_unique(rPalette); + case 24: + return std::make_unique(); + case 32: + return std::make_unique(); + default: + assert(false); + break; + } + return nullptr; +} +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/bitmap/impoctree.hxx b/vcl/inc/bitmap/impoctree.hxx new file mode 100644 index 000000000..06fbd6924 --- /dev/null +++ b/vcl/inc/bitmap/impoctree.hxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPOCTREE_HXX +#define INCLUDED_VCL_INC_IMPOCTREE_HXX + +#include "Octree.hxx" + +class ImpErrorQuad +{ + long nRed; + long nGreen; + long nBlue; + +public: + ImpErrorQuad() + : nRed(0) + , nGreen(0) + , nBlue(0) + { + } + + ImpErrorQuad(const BitmapColor& rColor) + : nRed(long(rColor.GetRed()) << 5) + , nGreen(long(rColor.GetGreen()) << 5) + , nBlue(long(rColor.GetBlue()) << 5) + { + } + + 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()) << 5; + nGreen = long(rColor.GetGreen()) << 5; + nBlue = long(rColor.GetBlue()) << 5; +} + +inline ImpErrorQuad& ImpErrorQuad::operator-=(const BitmapColor& rColor) +{ + nRed -= long(rColor.GetRed()) << 5; + nGreen -= long(rColor.GetGreen()) << 5; + nBlue -= long(rColor.GetBlue()) << 5; + + return *this; +} + +inline void ImpErrorQuad::ImplAddColorError1(const ImpErrorQuad& rErrQuad) +{ + nRed += rErrQuad.nRed >> 4; + nGreen += rErrQuad.nGreen >> 4; + nBlue += rErrQuad.nBlue >> 4; +} + +inline void ImpErrorQuad::ImplAddColorError3(const ImpErrorQuad& rErrQuad) +{ + nRed += rErrQuad.nRed * 3L >> 4; + nGreen += rErrQuad.nGreen * 3L >> 4; + nBlue += rErrQuad.nBlue * 3L >> 4; +} + +inline void ImpErrorQuad::ImplAddColorError5(const ImpErrorQuad& rErrQuad) +{ + nRed += rErrQuad.nRed * 5L >> 4; + nGreen += rErrQuad.nGreen * 5L >> 4; + nBlue += rErrQuad.nBlue * 5L >> 4; +} + +inline void ImpErrorQuad::ImplAddColorError7(const ImpErrorQuad& rErrQuad) +{ + nRed += rErrQuad.nRed * 7L >> 4; + nGreen += rErrQuad.nGreen * 7L >> 4; + nBlue += rErrQuad.nBlue * 7L >> 4; +} + +inline BitmapColor ImpErrorQuad::ImplGetColor() +{ + return BitmapColor(std::clamp(nRed, 0L, 8160L) >> 5, std::clamp(nGreen, 0L, 8160L) >> 5, + std::clamp(nBlue, 0L, 8160L) >> 5); +} + +#endif // INCLUDED_VCL_INC_IMPOCTREE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/bitmaps.hlst b/vcl/inc/bitmaps.hlst new file mode 100644 index 000000000..68f23533e --- /dev/null +++ b/vcl/inc/bitmaps.hlst @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_BITMAPS_HRC +#define INCLUDED_VCL_INC_BITMAPS_HRC + +#define SV_RESID_BITMAP_CHECK1 "vcl/res/check1.png" +#define SV_RESID_BITMAP_CHECK2 "vcl/res/check2.png" +#define SV_RESID_BITMAP_CHECK3 "vcl/res/check3.png" +#define SV_RESID_BITMAP_CHECK4 "vcl/res/check4.png" +#define SV_RESID_BITMAP_CHECK5 "vcl/res/check5.png" +#define SV_RESID_BITMAP_CHECK6 "vcl/res/check6.png" +#define SV_RESID_BITMAP_CHECK7 "vcl/res/check7.png" +#define SV_RESID_BITMAP_CHECK8 "vcl/res/check8.png" +#define SV_RESID_BITMAP_CHECK9 "vcl/res/check9.png" +#define SV_RESID_BITMAP_CHECKMONO1 "vcl/res/checkmono1.png" +#define SV_RESID_BITMAP_CHECKMONO2 "vcl/res/checkmono2.png" +#define SV_RESID_BITMAP_CHECKMONO3 "vcl/res/checkmono3.png" +#define SV_RESID_BITMAP_CHECKMONO4 "vcl/res/checkmono4.png" +#define SV_RESID_BITMAP_CHECKMONO5 "vcl/res/checkmono5.png" +#define SV_RESID_BITMAP_CHECKMONO6 "vcl/res/checkmono6.png" +#define SV_RESID_BITMAP_CHECKMONO7 "vcl/res/checkmono7.png" +#define SV_RESID_BITMAP_CHECKMONO8 "vcl/res/checkmono8.png" +#define SV_RESID_BITMAP_CHECKMONO9 "vcl/res/checkmono9.png" +#define SV_RESID_BITMAP_RADIO1 "vcl/res/radio1.png" +#define SV_RESID_BITMAP_RADIO2 "vcl/res/radio2.png" +#define SV_RESID_BITMAP_RADIO3 "vcl/res/radio3.png" +#define SV_RESID_BITMAP_RADIO4 "vcl/res/radio4.png" +#define SV_RESID_BITMAP_RADIO5 "vcl/res/radio5.png" +#define SV_RESID_BITMAP_RADIO6 "vcl/res/radio6.png" +#define SV_RESID_BITMAP_RADIOMONO1 "vcl/res/radiomono1.png" +#define SV_RESID_BITMAP_RADIOMONO2 "vcl/res/radiomono2.png" +#define SV_RESID_BITMAP_RADIOMONO3 "vcl/res/radiomono3.png" +#define SV_RESID_BITMAP_RADIOMONO4 "vcl/res/radiomono4.png" +#define SV_RESID_BITMAP_RADIOMONO5 "vcl/res/radiomono5.png" +#define SV_RESID_BITMAP_RADIOMONO6 "vcl/res/radiomono6.png" + +#define SV_RESID_BITMAP_ERRORBOX "vcl/res/errorbox.png" +#define SV_RESID_BITMAP_QUERYBOX "vcl/res/querybox.png" +#define SV_RESID_BITMAP_WARNINGBOX "vcl/res/warningbox.png" +#define SV_RESID_BITMAP_INFOBOX "vcl/res/infobox.png" + +#define SV_RESID_BITMAP_SCROLLMSK "vcl/res/scrmsk.png" +#define SV_RESID_BITMAP_WHEELVH "vcl/res/wheelvh.png" +#define SV_RESID_BITMAP_WHEELV "vcl/res/wheelv.png" +#define SV_RESID_BITMAP_WHEELH "vcl/res/wheelh.png" +#define SV_RESID_BITMAP_SCROLLVH "vcl/res/scrollvh.png" +#define SV_RESID_BITMAP_SCROLLV "vcl/res/scrollv.png" +#define SV_RESID_BITMAP_SCROLLH "vcl/res/scrollh.png" +#define SV_RESID_BITMAP_CLOSEDOC "vcl/res/closedoc.png" +#define SV_RESID_BITMAP_INDEX "vcl/res/index.png" +#define SV_RESID_BITMAP_REFRESH "res/reload.png" +#define SV_RESID_BITMAP_NOTEBOOKBAR "res/notebookbar.png" + +#define SV_DISCLOSURE_PLUS "res/plus.png" +#define SV_DISCLOSURE_MINUS "res/minus.png" + +#define SV_PRINT_COLLATE_BMP "vcl/res/collate.png" +#define SV_PRINT_NOCOLLATE_BMP "vcl/res/ncollate.png" + +#define MAINAPP_48_8 "res/mainapp_48_8.png" +#define ODT_48_8 "res/odt_48_8.png" +#define OTT_48_8 "res/ott_48_8.png" +#define ODS_48_8 "res/ods_48_8.png" +#define OTS_48_8 "res/ots_48_8.png" +#define ODG_48_8 "res/odg_48_8.png" +#define ODP_48_8 "res/odp_48_8.png" +#define ODM_48_8 "res/odm_48_8.png" +#define ODB_48_8 "res/odb_48_8.png" +#define ODF_48_8 "res/odf_48_8.png" + +#define MAINAPP_32_8 "res/mainapp_32_8.png" +#define ODT_32_8 "res/odt_32_8.png" +#define OTT_32_8 "res/ott_32_8.png" +#define ODS_32_8 "res/ods_32_8.png" +#define OTS_32_8 "res/ots_32_8.png" +#define ODG_32_8 "res/odg_32_8.png" +#define ODP_32_8 "res/odp_32_8.png" +#define ODM_32_8 "res/odm_32_8.png" +#define ODB_32_8 "res/odb_32_8.png" +#define ODF_32_8 "res/odf_32_8.png" + +#define MAINAPP_16_8 "res/mainapp_16_8.png" +#define ODT_16_8 "res/odt_16_8.png" +#define OTT_16_8 "res/ott_16_8.png" +#define ODS_16_8 "res/ods_16_8.png" +#define OTS_16_8 "res/ots_16_8.png" +#define ODG_16_8 "res/odg_16_8.png" +#define ODP_16_8 "res/odp_16_8.png" +#define ODM_16_8 "res/odm_16_8.png" +#define ODB_16_8 "res/odb_16_8.png" +#define ODF_16_8 "res/odf_16_8.png" + +//start, Throbber::getDefaultImageURLs +#define SPINNER_16_01 "vcl/res/spinner-16-01.png" +#define SPINNER_16_02 "vcl/res/spinner-16-02.png" +#define SPINNER_16_03 "vcl/res/spinner-16-03.png" +#define SPINNER_16_04 "vcl/res/spinner-16-04.png" +#define SPINNER_16_05 "vcl/res/spinner-16-05.png" +#define SPINNER_16_06 "vcl/res/spinner-16-06.png" + +#define SPINNER_32_01 "vcl/res/spinner-32-01.png" +#define SPINNER_32_02 "vcl/res/spinner-32-02.png" +#define SPINNER_32_03 "vcl/res/spinner-32-03.png" +#define SPINNER_32_04 "vcl/res/spinner-32-04.png" +#define SPINNER_32_05 "vcl/res/spinner-32-05.png" +#define SPINNER_32_06 "vcl/res/spinner-32-06.png" +#define SPINNER_32_07 "vcl/res/spinner-32-07.png" +#define SPINNER_32_08 "vcl/res/spinner-32-08.png" +#define SPINNER_32_09 "vcl/res/spinner-32-09.png" +#define SPINNER_32_10 "vcl/res/spinner-32-10.png" +#define SPINNER_32_11 "vcl/res/spinner-32-11.png" +#define SPINNER_32_12 "vcl/res/spinner-32-12.png" + +#define SPINNER_64_01 "vcl/res/spinner-64-01.png" +#define SPINNER_64_02 "vcl/res/spinner-64-02.png" +#define SPINNER_64_03 "vcl/res/spinner-64-03.png" +#define SPINNER_64_04 "vcl/res/spinner-64-04.png" +#define SPINNER_64_05 "vcl/res/spinner-64-05.png" +#define SPINNER_64_06 "vcl/res/spinner-64-06.png" +#define SPINNER_64_07 "vcl/res/spinner-64-07.png" +#define SPINNER_64_08 "vcl/res/spinner-64-08.png" +#define SPINNER_64_09 "vcl/res/spinner-64-09.png" +#define SPINNER_64_10 "vcl/res/spinner-64-10.png" +#define SPINNER_64_11 "vcl/res/spinner-64-11.png" +#define SPINNER_64_12 "vcl/res/spinner-64-12.png" +//end, Throbber::getDefaultImageURLs + +#define IMG_APPLY "sw/res/sc20558.png" +#define IMG_WARN "dbaccess/res/exwarning.png" +#define IMG_ERROR "dbaccess/res/exerror.png" +#define IMG_INFO "dbaccess/res/exinfo.png" +#define IMG_ADD "extensions/res/scanner/plus.png" +#define IMG_REMOVE "extensions/res/scanner/minus.png" +#define IMG_COPY "cmd/sc_copy.png" +#define IMG_PASTE "cmd/sc_paste.png" + +#define RID_BMP_TREENODE_COLLAPSED "res/plus.png" +#define RID_BMP_TREENODE_EXPANDED "res/minus.png" + +#define RID_CURSOR_AUTOSCROLL_E "vcl/res/autoscroll_e.png" +#define RID_CURSOR_AUTOSCROLL_N "vcl/res/autoscroll_n.png" +#define RID_CURSOR_AUTOSCROLL_NE "vcl/res/autoscroll_ne.png" +#define RID_CURSOR_AUTOSCROLL_NS "vcl/res/autoscroll_ns.png" +#define RID_CURSOR_AUTOSCROLL_NSWE "vcl/res/autoscroll_nswe.png" +#define RID_CURSOR_AUTOSCROLL_NW "vcl/res/autoscroll_nw.png" +#define RID_CURSOR_AUTOSCROLL_S "vcl/res/autoscroll_s.png" +#define RID_CURSOR_AUTOSCROLL_SE "vcl/res/autoscroll_se.png" +#define RID_CURSOR_AUTOSCROLL_SW "vcl/res/autoscroll_sw.png" +#define RID_CURSOR_AUTOSCROLL_W "vcl/res/autoscroll_w.png" +#define RID_CURSOR_AUTOSCROLL_WE "vcl/res/autoscroll_we.png" +#define RID_CURSOR_CHAIN "vcl/res/chain.png" +#define RID_CURSOR_CHAIN_NOT_ALLOWED "vcl/res/chain_not_allowed.png" +#define RID_CURSOR_CHART "vcl/res/chart.png" +#define RID_CURSOR_COPY_DATA "vcl/res/copy_data.png" +#define RID_CURSOR_COPY_DATA_LINK "vcl/res/copy_data_link.png" +#define RID_CURSOR_COPY_FILE "vcl/res/copy_file.png" +#define RID_CURSOR_COPY_FILES "vcl/res/copy_files.png" +#define RID_CURSOR_COPY_FILE_LINK "vcl/res/copy_file_link.png" +#define RID_CURSOR_CROOK "vcl/res/crook.png" +#define RID_CURSOR_CROP "vcl/res/crop.png" +#define RID_CURSOR_DRAW_ARC "vcl/res/draw_arc.png" +#define RID_CURSOR_DRAW_BEZIER "vcl/res/draw_bezier.png" +#define RID_CURSOR_DRAW_CAPTION "vcl/res/draw_caption.png" +#define RID_CURSOR_DRAW_CIRCLE_CUT "vcl/res/draw_circle_cut.png" +#define RID_CURSOR_DRAW_CONNECT "vcl/res/draw_connect.png" +#define RID_CURSOR_DRAW_ELLIPSE "vcl/res/draw_ellipse.png" +#define RID_CURSOR_DETECTIVE "vcl/res/detective.png" +#define RID_CURSOR_DRAW_FREEHAND "vcl/res/draw_freehand.png" +#define RID_CURSOR_DRAW_LINE "vcl/res/draw_line.png" +#define RID_CURSOR_DRAW_PIE "vcl/res/draw_pie.png" +#define RID_CURSOR_DRAW_POLYGON "vcl/res/draw_polygon.png" +#define RID_CURSOR_DRAW_RECT "vcl/res/draw_rect.png" +#define RID_CURSOR_DRAW_TEXT "vcl/res/draw_text.png" +#define RID_CURSOR_FILL "vcl/res/fill.png" +#define RID_CURSOR_HELP "vcl/res/help.png" +#define RID_CURSOR_H_SHEAR "vcl/res/h_shear.png" +#define RID_CURSOR_LINK_DATA "vcl/res/link_data.png" +#define RID_CURSOR_LINK_FILE "vcl/res/link_file.png" +#define RID_CURSOR_MAGNIFY "vcl/res/magnify.png" +#define RID_CURSOR_MIRROR "vcl/res/mirror.png" +#define RID_CURSOR_MOVE_BEZIER_WEIGHT "vcl/res/move_bezier_weight.png" +#define RID_CURSOR_MOVE_DATA "vcl/res/move_data.png" +#define RID_CURSOR_MOVE_DATA_LINK "vcl/res/move_data_link.png" +#define RID_CURSOR_MOVE_FILE "vcl/res/move_file.png" +#define RID_CURSOR_MOVE_FILES "vcl/res/move_files.png" +#define RID_CURSOR_MOVE_FILE_LINK "vcl/res/move_file_link.png" +#define RID_CURSOR_MOVE_POINT "vcl/res/move_point.png" +#define RID_CURSOR_NESWSIZE "vcl/res/neswsize.png" +#define RID_CURSOR_NOT_ALLOWED "vcl/res/not_allowed.png" +#define RID_CURSOR_NULL "vcl/res/null.png" +#define RID_CURSOR_NWSESIZE "vcl/res/nwsesize.png" +#define RID_CURSOR_PEN "vcl/res/pen.png" +#define RID_CURSOR_PIVOT_COLUMN "vcl/res/pivot_column.png" +#define RID_CURSOR_PIVOT_DELETE "vcl/res/pivot_delete.png" +#define RID_CURSOR_PIVOT_FIELD "vcl/res/pivot_field.png" +#define RID_CURSOR_PIVOT_ROW "vcl/res/pivot_row.png" +#define RID_CURSOR_ROTATE "vcl/res/rotate.png" +#define RID_CURSOR_TAB_SELECT_E "vcl/res/tab_select_e.png" +#define RID_CURSOR_TAB_SELECT_S "vcl/res/tab_select_s.png" +#define RID_CURSOR_TAB_SELECT_SE "vcl/res/tab_select_se.png" +#define RID_CURSOR_TAB_SELECT_SW "vcl/res/tab_select_sw.png" +#define RID_CURSOR_TAB_SELECT_W "vcl/res/tab_select_w.png" +#define RID_CURSOR_V_SHEAR "vcl/res/v_shear.png" +#define RID_CURSOR_TEXT_VERTICAL "vcl/res/text_vertical.png" +#define RID_CURSOR_HIDE_WHITESPACE "vcl/res/hide_whitespace.png" +#define RID_CURSOR_SHOW_WHITESPACE "vcl/res/show_whitespace.png" +#define RID_CURSOR_WAIT "vcl/res/wait.png" +#define RID_CURSOR_NWSIZE "vcl/res/nwsize.png" +#define RID_CURSOR_NESIZE "vcl/res/nesize.png" +#define RID_CURSOR_SWSIZE "vcl/res/swsize.png" +#define RID_CURSOR_SESIZE "vcl/res/sesize.png" +#define RID_CURSOR_WINDOW_NWSIZE "vcl/res/window_nwsize.png" +#define RID_CURSOR_WINDOW_NESIZE "vcl/res/window_nesize.png" +#define RID_CURSOR_WINDOW_SWSIZE "vcl/res/window_swsize.png" +#define RID_CURSOR_WINDOW_SESIZE "vcl/res/window_sesize.png" + +#define CHEVRON "sfx2/res/chevron.png" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/bitmapwriteaccess.hxx b/vcl/inc/bitmapwriteaccess.hxx new file mode 100644 index 000000000..f747223ec --- /dev/null +++ b/vcl/inc/bitmapwriteaccess.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_BITMAPWRITEACCESS_HXX +#define INCLUDED_VCL_INC_BITMAPWRITEACCESS_HXX + +#include +#include +#include +#include + +typedef vcl::ScopedBitmapAccess + BitmapScopedWriteAccess; + +typedef vcl::ScopedBitmapAccess + AlphaScopedWriteAccess; + +class VCL_DLLPUBLIC BitmapWriteAccess : public BitmapReadAccess +{ +public: + BitmapWriteAccess(Bitmap& rBitmap); + virtual ~BitmapWriteAccess() override; + + void CopyScanline(long nY, const BitmapReadAccess& rReadAcc); + void CopyScanline(long nY, ConstScanline aSrcScanline, ScanlineFormat nSrcScanlineFormat, + sal_uInt32 nSrcScanlineSize); + + void SetPalette(const BitmapPalette& rPalette) + { + assert(mpBuffer && "Access is not valid!"); + + mpBuffer->maPalette = rPalette; + } + + void SetPaletteEntryCount(sal_uInt16 nCount) + { + assert(mpBuffer && "Access is not valid!"); + + mpBuffer->maPalette.SetEntryCount(nCount); + } + + void SetPaletteColor(sal_uInt16 nColor, const BitmapColor& rBitmapColor) + { + assert(mpBuffer && "Access is not valid!"); + assert(HasPalette() && "Bitmap has no palette!"); + + mpBuffer->maPalette[nColor] = rBitmapColor; + } + + void SetPixel(long nY, long nX, const BitmapColor& rBitmapColor) + { + assert(mpBuffer && "Access is not valid!"); + assert(nX < mpBuffer->mnWidth && "x-coordinate out of range!"); + assert(nY < mpBuffer->mnHeight && "y-coordinate out of range!"); + + mFncSetPixel(GetScanline(nY), nX, rBitmapColor, maColorMask); + } + + void SetPixelIndex(long nY, long nX, sal_uInt8 cIndex) + { + SetPixel(nY, nX, BitmapColor(cIndex)); + } + + void SetLineColor(const Color& rColor); + + void SetFillColor(); + void SetFillColor(const Color& rColor); + + void Erase(const Color& rColor); + + void DrawLine(const Point& rStart, const Point& rEnd); + + void FillRect(const tools::Rectangle& rRect); + void DrawRect(const tools::Rectangle& rRect); + +private: + std::optional mpLineColor; + std::optional mpFillColor; + + BitmapWriteAccess() = delete; + BitmapWriteAccess(const BitmapWriteAccess&) = delete; + BitmapWriteAccess& operator=(const BitmapWriteAccess&) = delete; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/bmpfast.hxx b/vcl/inc/bmpfast.hxx new file mode 100644 index 000000000..f9a1f891b --- /dev/null +++ b/vcl/inc/bmpfast.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_BMPFAST_HXX +#define INCLUDED_VCL_INC_BMPFAST_HXX + +#include + +class BitmapWriteAccess; +class BitmapReadAccess; +struct BitmapBuffer; +class BitmapColor; +struct SalTwoRect; + +// the bmpfast functions have signatures with good compatibility to +// their canonic counterparts, which employ the GetPixel/SetPixel methods + +VCL_DLLPUBLIC bool ImplFastBitmapConversion( BitmapBuffer& rDst, const BitmapBuffer& rSrc, + const SalTwoRect& rTwoRect ); + +bool ImplFastBitmapBlending( BitmapWriteAccess const & rDst, + const BitmapReadAccess& rSrc, const BitmapReadAccess& rMask, + const SalTwoRect& rTwoRect ); + +bool ImplFastEraseBitmap( BitmapBuffer&, const BitmapColor& ); + +#endif // INCLUDED_VCL_INC_BMPFAST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/brdwin.hxx b/vcl/inc/brdwin.hxx new file mode 100644 index 000000000..1dedce0e2 --- /dev/null +++ b/vcl/inc/brdwin.hxx @@ -0,0 +1,294 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_BRDWIN_HXX +#define INCLUDED_VCL_INC_BRDWIN_HXX + +#include +#include +#include +#include + +#include + +class ImplBorderWindowView; +enum class DrawButtonFlags; + +enum class BorderWindowStyle { + NONE = 0x0000, + Overlap = 0x0001, + Float = 0x0004, + Frame = 0x0008, + App = 0x0010 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +enum class BorderWindowHitTest { + NONE = 0x0000, + Title = 0x0001, + Left = 0x0002, + Menu = 0x0004, + Top = 0x0008, + Right = 0x0010, + Bottom = 0x0020, + TopLeft = 0x0040, + TopRight = 0x0080, + BottomLeft = 0x0100, + BottomRight = 0x0200, + Close = 0x0400, + Roll = 0x0800, + Dock = 0x1000, + Hide = 0x2000, + Help = 0x4000, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +enum class BorderWindowTitleType { + Normal = 0x0001, + Small = 0x0002, + Tearoff = 0x0004, + Popup = 0x0008, + NONE = 0x0010 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +class ImplBorderWindow : public vcl::Window +{ + friend class vcl::Window; + friend class ImplBorderWindowView; + friend class ImplSmallBorderWindowView; + friend class ImplStdBorderWindowView; + +private: + std::unique_ptr mpBorderView; + VclPtr mpMenuBarWindow; + VclPtr mpNotebookBar; + long mnMinWidth; + long mnMinHeight; + long mnMaxWidth; + long mnMaxHeight; + long mnOrgMenuHeight; + BorderWindowTitleType mnTitleType; + WindowBorderStyle mnBorderStyle; + bool mbFloatWindow; + bool mbSmallOutBorder; + bool mbFrameBorder; + bool mbRollUp; + bool mbMenuHide; + bool mbDockBtn; + bool mbHideBtn; + bool mbMenuBtn; + bool mbDisplayActive; + + using Window::ImplInit; + void ImplInit( vcl::Window* pParent, + WinBits nStyle, BorderWindowStyle nTypeStyle, + SystemParentData* pParentData ); + + ImplBorderWindow (const ImplBorderWindow &) = delete; + ImplBorderWindow& operator= (const ImplBorderWindow &) = delete; + +public: + ImplBorderWindow( vcl::Window* pParent, + SystemParentData* pParentData, + WinBits nStyle, + BorderWindowStyle nTypeStyle ); + ImplBorderWindow( vcl::Window* pParent, WinBits nStyle, + BorderWindowStyle nTypeStyle ); + virtual ~ImplBorderWindow() override; + virtual void dispose() override; + + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual void Activate() override; + virtual void Deactivate() override; + virtual void Resize() override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + virtual void StateChanged( StateChangedType nType ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void queue_resize(StateChangedType eReason = StateChangedType::Layout) override; + + void InitView(); + void UpdateView( bool bNewView, const Size& rNewOutSize ); + void InvalidateBorder(); + + using Window::Draw; + void Draw( OutputDevice* pDev, const Point& rPos ); + + void SetDisplayActive( bool bActive ); + void SetTitleType( BorderWindowTitleType nTitleType, const Size& rSize ); + void SetBorderStyle( WindowBorderStyle nStyle ); + WindowBorderStyle GetBorderStyle() const { return mnBorderStyle; } + void SetRollUp( bool bRollUp, const Size& rSize ); + void SetCloseButton(); + void SetDockButton( bool bDockButton ); + void SetHideButton( bool bHideButton ); + void SetMenuButton( bool bMenuButton ); + + void UpdateMenuHeight(); + void SetMenuBarWindow( vcl::Window* pWindow ); + void SetMenuBarMode( bool bHide ); + + void SetNotebookBar(const OUString& rUIXMLDescription, + const css::uno::Reference& rFrame, + const NotebookBarAddonsItem &aNotebookBarAddonsItem); + void CloseNotebookBar(); + const VclPtr& GetNotebookBar() const { return mpNotebookBar; } + + 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; + + tools::Rectangle GetMenuRect() const; + + virtual Size GetOptimalSize() const override; +}; + +struct ImplBorderFrameData +{ + VclPtr mpBorderWindow; + VclPtr mpOutDev; + tools::Rectangle maTitleRect; + tools::Rectangle maCloseRect; + tools::Rectangle maRollRect; + tools::Rectangle maDockRect; + tools::Rectangle maMenuRect; + tools::Rectangle maHideRect; + tools::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; + BorderWindowHitTest mnHitTest; + DrawButtonFlags mnCloseState; + DrawButtonFlags mnRollState; + DrawButtonFlags mnDockState; + DrawButtonFlags mnMenuState; + DrawButtonFlags mnHideState; + DrawButtonFlags mnHelpState; + BorderWindowTitleType mnTitleType; + bool mbDragFull; + bool mbTitleClipped; +}; + +class ImplBorderWindowView +{ +public: + virtual ~ImplBorderWindowView(); + + virtual bool MouseMove( const MouseEvent& rMEvt ); + virtual bool MouseButtonDown( const MouseEvent& rMEvt ); + virtual bool Tracking( const TrackingEvent& rTEvt ); + virtual OUString RequestHelp( const Point& rPos, tools::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(vcl::RenderContext& rRenderContext, const Point* pOffset = nullptr) = 0; + virtual tools::Rectangle GetMenuRect() const; + + static void ImplInitTitle( ImplBorderFrameData* pData ); + static BorderWindowHitTest ImplHitTest( ImplBorderFrameData const * pData, const Point& rPos ); + static void ImplMouseMove( ImplBorderFrameData* pData, const MouseEvent& rMEvt ); + static OUString ImplRequestHelp( ImplBorderFrameData const * pData, const Point& rPos, tools::Rectangle& rHelpRect ); + static long ImplCalcTitleWidth( const ImplBorderFrameData* pData ); +}; + +class ImplNoBorderWindowView final : public ImplBorderWindowView +{ +public: + ImplNoBorderWindowView(); + + virtual void Init( OutputDevice* pDev, long nWidth, long nHeight ) override; + virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const override; + virtual long CalcTitleWidth() const override; + virtual void DrawWindow(vcl::RenderContext& rRenderContext, const Point* pOffset = nullptr) override; +}; + +class ImplSmallBorderWindowView : public ImplBorderWindowView +{ + VclPtr mpBorderWindow; + VclPtr 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 ) override; + virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const override; + virtual long CalcTitleWidth() const override; + virtual void DrawWindow(vcl::RenderContext& rRenderContext, const Point* pOffset = nullptr) override; +}; + +class ImplStdBorderWindowView : public ImplBorderWindowView +{ + ImplBorderFrameData maFrameData; + +public: + ImplStdBorderWindowView( ImplBorderWindow* pBorderWindow ); + virtual ~ImplStdBorderWindowView() override; + + virtual bool MouseMove( const MouseEvent& rMEvt ) override; + virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual bool Tracking( const TrackingEvent& rTEvt ) override; + virtual OUString RequestHelp( const Point& rPos, tools::Rectangle& rHelpRect ) override; + virtual tools::Rectangle GetMenuRect() const override; + + virtual void Init( OutputDevice* pDev, long nWidth, long nHeight ) override; + virtual void GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const override; + virtual long CalcTitleWidth() const override; + virtual void DrawWindow(vcl::RenderContext& rRenderContext, const Point* pOffset = nullptr) override; +}; + +#endif // INCLUDED_VCL_INC_BRDWIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/canvasbitmap.hxx b/vcl/inc/canvasbitmap.hxx new file mode 100644 index 000000000..e49f3f43a --- /dev/null +++ b/vcl/inc/canvasbitmap.hxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_CANVASBITMAP_HXX +#define INCLUDED_VCL_INC_CANVASBITMAP_HXX + +#include +#include +#include +#include + +#include + +namespace vcl +{ +namespace unotools +{ + class VCL_DLLPUBLIC VclCanvasBitmap final : + public cppu::WeakImplHelper< css::rendering::XIntegerReadOnlyBitmap, + css::rendering::XBitmapPalette, + css::rendering::XIntegerBitmapColorSpace > + { + private: + BitmapEx m_aBmpEx; + ::Bitmap m_aBitmap; + ::Bitmap m_aAlpha; + Bitmap::ScopedReadAccess m_pBmpAcc; + Bitmap::ScopedReadAccess m_pAlphaAcc; + css::uno::Sequence m_aComponentTags; + css::uno::Sequence m_aComponentBitCounts; + css::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_bPalette; + + SAL_DLLPRIVATE void setComponentInfo( sal_uInt32 redShift, sal_uInt32 greenShift, sal_uInt32 blueShift ); + + virtual ~VclCanvasBitmap() override; + + public: + // XBitmap + virtual css::geometry::IntegerSize2D SAL_CALL getSize() override; + virtual sal_Bool SAL_CALL hasAlpha( ) override; + virtual css::uno::Reference< css::rendering::XBitmap > SAL_CALL getScaledBitmap( const css::geometry::RealSize2D& newSize, sal_Bool beFast ) override; + + // XIntegerReadOnlyBitmap + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getData( css::rendering::IntegerBitmapLayout& bitmapLayout, const css::geometry::IntegerRectangle2D& rect ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getPixel( css::rendering::IntegerBitmapLayout& bitmapLayout, const css::geometry::IntegerPoint2D& pos ) override; + /// @throws css::uno::RuntimeException + css::uno::Reference< css::rendering::XBitmapPalette > getPalette( ); + virtual css::rendering::IntegerBitmapLayout SAL_CALL getMemoryLayout( ) override; + + // XBitmapPalette + virtual sal_Int32 SAL_CALL getNumberOfEntries() override; + virtual sal_Bool SAL_CALL getIndex( css::uno::Sequence< double >& entry, ::sal_Int32 nIndex ) override; + virtual sal_Bool SAL_CALL setIndex( const css::uno::Sequence< double >& color, sal_Bool transparency, ::sal_Int32 nIndex ) override; + virtual css::uno::Reference< css::rendering::XColorSpace > SAL_CALL getColorSpace( ) override; + + // XIntegerBitmapColorSpace + virtual ::sal_Int8 SAL_CALL getType( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getComponentTags( ) override; + virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override; + virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getProperties( ) override; + virtual css::uno::Sequence< double > SAL_CALL convertColorSpace( const css::uno::Sequence< double >& deviceColor, const css::uno::Reference< css::rendering::XColorSpace >& targetColorSpace ) override; + virtual css::uno::Sequence< css::rendering::RGBColor > SAL_CALL convertToRGB( const css::uno::Sequence< double >& deviceColor ) override; + virtual css::uno::Sequence< css::rendering::ARGBColor > SAL_CALL convertToARGB( const css::uno::Sequence< double >& deviceColor ) override; + virtual css::uno::Sequence< css::rendering::ARGBColor > SAL_CALL convertToPARGB( const css::uno::Sequence< double >& deviceColor ) override; + virtual css::uno::Sequence< double > SAL_CALL convertFromRGB( const css::uno::Sequence< css::rendering::RGBColor >& rgbColor ) override; + virtual css::uno::Sequence< double > SAL_CALL convertFromARGB( const css::uno::Sequence< css::rendering::ARGBColor >& rgbColor ) override; + virtual css::uno::Sequence< double > SAL_CALL convertFromPARGB( const css::uno::Sequence< css::rendering::ARGBColor >& rgbColor ) override; + virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override; + virtual css::uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override; + virtual ::sal_Int8 SAL_CALL getEndianness( ) override; + virtual css::uno::Sequence SAL_CALL convertFromIntegerColorSpace( const css::uno::Sequence< ::sal_Int8 >& deviceColor, const css::uno::Reference< css::rendering::XColorSpace >& targetColorSpace ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const css::uno::Sequence< ::sal_Int8 >& deviceColor, const css::uno::Reference< css::rendering::XIntegerBitmapColorSpace >& targetColorSpace ) override; + virtual css::uno::Sequence< css::rendering::RGBColor > SAL_CALL convertIntegerToRGB( const css::uno::Sequence< ::sal_Int8 >& deviceColor ) override; + virtual css::uno::Sequence< css::rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const css::uno::Sequence< ::sal_Int8 >& deviceColor ) override; + virtual css::uno::Sequence< css::rendering::ARGBColor > SAL_CALL convertIntegerToPARGB( const css::uno::Sequence< ::sal_Int8 >& deviceColor ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromRGB( const css::uno::Sequence< css::rendering::RGBColor >& rgbColor ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const css::uno::Sequence< css::rendering::ARGBColor >& rgbColor ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const css::uno::Sequence< css::rendering::ARGBColor >& rgbColor ) override; + + /** 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! + const BitmapEx& getBitmapEx() const { return m_aBmpEx; } + }; +} +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/configsettings.hxx b/vcl/inc/configsettings.hxx new file mode 100644 index 000000000..ea6cf6574 --- /dev/null +++ b/vcl/inc/configsettings.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_CONFIGSETTINGS_HXX +#define INCLUDED_VCL_CONFIGSETTINGS_HXX + +#include +#include +#include + +#include + +namespace com::sun::star::uno { template class Sequence; } + +namespace vcl +{ + typedef std::unordered_map< OUString, OUString > OUStrMap; + class SmallOUStrMap : public OUStrMap { public: SmallOUStrMap() : OUStrMap(1) {} }; + + + //= SettingsConfigItem + + class VCL_DLLPUBLIC SettingsConfigItem final : public ::utl::ConfigItem + { + private: + std::unordered_map< OUString, SmallOUStrMap > m_aSettings; + + virtual void Notify( const css::uno::Sequence< OUString >& rPropertyNames ) override; + + void getValues(); + SettingsConfigItem(); + + virtual void ImplCommit() override; + + public: + virtual ~SettingsConfigItem() override; + + static SettingsConfigItem* get(); + + OUString getValue( const OUString& rGroup, const OUString& rKey ) const; + void setValue( const OUString& rGroup, const OUString& rKey, const OUString& rValue ); + + }; + + +} // namespace vcl + + +#endif // INCLUDED_VCL_CONFIGSETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/controldata.hxx b/vcl/inc/controldata.hxx new file mode 100644 index 000000000..ed6e3a368 --- /dev/null +++ b/vcl/inc/controldata.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_CONTROLDATA_HXX +#define INCLUDED_VCL_INC_CONTROLDATA_HXX + +#include +#include + +namespace vcl +{ + struct ImplControlData + { + mutable std::unique_ptr mpLayoutData; + VclPtr mpReferenceDevice; + }; + +} // namespace vcl + +#endif // INCLUDED_VCL_INC_CONTROLDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/cursor_hotspots.hxx b/vcl/inc/cursor_hotspots.hxx new file mode 100644 index 000000000..74a041ddd --- /dev/null +++ b/vcl/inc/cursor_hotspots.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_CURSOR_HOTSPOTS_HXX +#define INCLUDED_VCL_INC_CURSOR_HOTSPOTS_HXX + +#define help_curs_x_hot 0 +#define help_curs_y_hot 0 +#define pen_curs_x_hot 3 +#define pen_curs_y_hot 27 +#define nodrop_curs_x_hot 9 +#define nodrop_curs_y_hot 9 +#define magnify_curs_x_hot 12 +#define magnify_curs_y_hot 13 +#define rotate_curs_x_hot 15 +#define rotate_curs_y_hot 15 +#define hshear_curs_x_hot 15 +#define hshear_curs_y_hot 15 +#define vshear_curs_x_hot 15 +#define vshear_curs_y_hot 15 +#define drawline_curs_x_hot 7 +#define drawline_curs_y_hot 7 +#define drawrect_curs_x_hot 7 +#define drawrect_curs_y_hot 7 +#define drawpolygon_curs_x_hot 7 +#define drawpolygon_curs_y_hot 7 +#define drawbezier_curs_x_hot 7 +#define drawbezier_curs_y_hot 7 +#define drawarc_curs_x_hot 7 +#define drawarc_curs_y_hot 7 +#define drawpie_curs_x_hot 7 +#define drawpie_curs_y_hot 7 +#define drawcirclecut_curs_x_hot 7 +#define drawcirclecut_curs_y_hot 7 +#define drawellipse_curs_x_hot 7 +#define drawellipse_curs_y_hot 7 +#define drawconnect_curs_x_hot 7 +#define drawconnect_curs_y_hot 7 +#define drawtext_curs_x_hot 8 +#define drawtext_curs_y_hot 8 +#define mirror_curs_x_hot 14 +#define mirror_curs_y_hot 12 +#define crook_curs_x_hot 15 +#define crook_curs_y_hot 14 +#define crop_curs_x_hot 9 +#define crop_curs_y_hot 9 +#define movepoint_curs_x_hot 0 +#define movepoint_curs_y_hot 0 +#define movebezierweight_curs_x_hot 0 +#define movebezierweight_curs_y_hot 0 +#define drawfreehand_curs_x_hot 8 +#define drawfreehand_curs_y_hot 8 +#define drawcaption_curs_x_hot 8 +#define drawcaption_curs_y_hot 8 +#define movedata_curs_x_hot 1 +#define movedata_curs_y_hot 1 +#define copydata_curs_x_hot 1 +#define copydata_curs_y_hot 1 +#define linkdata_curs_x_hot 1 +#define linkdata_curs_y_hot 1 +#define movedlnk_curs_x_hot 1 +#define movedlnk_curs_y_hot 1 +#define copydlnk_curs_x_hot 1 +#define copydlnk_curs_y_hot 1 +#define movefile_curs_x_hot 9 +#define movefile_curs_y_hot 9 +#define copyfile_curs_x_hot 9 +#define copyfile_curs_y_hot 9 +#define linkfile_curs_x_hot 9 +#define linkfile_curs_y_hot 9 +#define moveflnk_curs_x_hot 9 +#define moveflnk_curs_y_hot 9 +#define copyflnk_curs_x_hot 9 +#define copyflnk_curs_y_hot 9 +#define movefiles_curs_x_hot 8 +#define movefiles_curs_y_hot 9 +#define copyfiles_curs_x_hot 8 +#define copyfiles_curs_y_hot 9 + +#define chart_curs_x_hot 15 +#define chart_curs_y_hot 16 +#define detective_curs_x_hot 12 +#define detective_curs_y_hot 13 +#define pivotcol_curs_x_hot 7 +#define pivotcol_curs_y_hot 5 +#define pivotfld_curs_x_hot 8 +#define pivotfld_curs_y_hot 7 +#define pivotrow_curs_x_hot 8 +#define pivotrow_curs_y_hot 7 +#define pivotdel_curs_x_hot 9 +#define pivotdel_curs_y_hot 8 + +#define chain_curs_x_hot 0 +#define chain_curs_y_hot 2 +#define chainnot_curs_x_hot 2 +#define chainnot_curs_y_hot 2 + +#define ase_curs_x_hot 19 +#define ase_curs_y_hot 16 +#define asn_curs_x_hot 16 +#define asn_curs_y_hot 12 +#define asne_curs_x_hot 21 +#define asne_curs_y_hot 10 +#define asns_curs_x_hot 15 +#define asns_curs_y_hot 15 +#define asnswe_curs_x_hot 15 +#define asnswe_curs_y_hot 15 +#define asnw_curs_x_hot 10 +#define asnw_curs_y_hot 10 +#define ass_curs_x_hot 15 +#define ass_curs_y_hot 19 +#define asse_curs_x_hot 21 +#define asse_curs_y_hot 21 +#define assw_curs_x_hot 10 +#define assw_curs_y_hot 21 +#define asw_curs_x_hot 12 +#define asw_curs_y_hot 15 +#define aswe_curs_x_hot 15 +#define aswe_curs_y_hot 15 +#define nullcurs_x_hot 2 +#define nullcurs_y_hot 2 + +#define fill_curs_x_hot 10 +#define fill_curs_y_hot 22 +#define vertcurs_curs_x_hot 8 +#define vertcurs_curs_y_hot 8 +#define tblsele_curs_x_hot 14 +#define tblsele_curs_y_hot 8 +#define tblsels_curs_x_hot 7 +#define tblsels_curs_y_hot 14 +#define tblselse_curs_x_hot 14 +#define tblselse_curs_y_hot 14 +#define tblselw_curs_x_hot 1 +#define tblselw_curs_y_hot 8 +#define tblselsw_curs_x_hot 1 +#define tblselsw_curs_y_hot 14 +#define hidewhitespace_curs_x_hot 0 +#define hidewhitespace_curs_y_hot 10 +#define showwhitespace_curs_x_hot 0 +#define showwhitespace_curs_y_hot 10 + +#define wait_curs_x_hot 10 +#define wait_curs_y_hot 10 +#define nwsize_curs_x_hot 10 +#define nwsize_curs_y_hot 10 +#define nesize_curs_x_hot 10 +#define nesize_curs_y_hot 10 +#define swsize_curs_x_hot 10 +#define swsize_curs_y_hot 10 +#define sesize_curs_x_hot 10 +#define sesize_curs_y_hot 10 +#define window_nwsize_curs_x_hot 10 +#define window_nwsize_curs_y_hot 10 +#define window_nesize_curs_x_hot 10 +#define window_nesize_curs_y_hot 10 +#define window_swsize_curs_x_hot 10 +#define window_swsize_curs_y_hot 10 +#define window_sesize_curs_x_hot 10 +#define window_sesize_curs_y_hot 10 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/dbggui.hxx b/vcl/inc/dbggui.hxx new file mode 100644 index 000000000..b3d93c5e1 --- /dev/null +++ b/vcl/inc/dbggui.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#ifndef NDEBUG + +void DbgGUIInitSolarMutexCheck(); +void DbgGUIDeInitSolarMutexCheck(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/debugevent.hxx b/vcl/inc/debugevent.hxx new file mode 100644 index 000000000..a6f458265 --- /dev/null +++ b/vcl/inc/debugevent.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_DEBUGEVENT_HXX +#define INCLUDED_VCL_DEBUGEVENT_HXX + +#include +#include +#include + +namespace vcl { class Window; } + +class DebugEventInjector final : private Timer { + sal_uInt32 mnEventsLeft; + DebugEventInjector( sal_uInt32 nMaxEvents ); + + static vcl::Window *ChooseWindow(); + static void InjectTextEvent(); + static void InjectMenuEvent(); + static void InjectEvent(); + static void InjectKeyNavEdit(); + virtual void Invoke() override; + + public: + static DebugEventInjector *getCreate(); +}; + +#endif // INCLUDED_VCL_DEBUGEVENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/displayconnectiondispatch.hxx b/vcl/inc/displayconnectiondispatch.hxx new file mode 100644 index 000000000..e988ee62f --- /dev/null +++ b/vcl/inc/displayconnectiondispatch.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_DISPLAYCONNECTIONDISPATCH_HXX +#define INCLUDED_VCL_INC_DISPLAYCONNECTIONDISPATCH_HXX + +#include +#include +#include +#include +#include +#include + +namespace vcl { + +class DisplayConnectionDispatch final : + public cppu::WeakImplHelper< css::awt::XDisplayConnection > +{ + ::osl::Mutex m_aMutex; + ::std::vector< css::uno::Reference< css::awt::XEventHandler > > + m_aHandlers; + OUString m_ConnectionIdentifier; +public: + DisplayConnectionDispatch(); + ~DisplayConnectionDispatch() override; + + void start(); + void terminate(); + + bool dispatchEvent( void const * pData, int nBytes ); + + // XDisplayConnection + virtual void SAL_CALL addEventHandler( const css::uno::Any& window, const css::uno::Reference< css::awt::XEventHandler >& handler, sal_Int32 eventMask ) override; + virtual void SAL_CALL removeEventHandler( const css::uno::Any& window, const css::uno::Reference< css::awt::XEventHandler >& handler ) override; + virtual void SAL_CALL addErrorHandler( const css::uno::Reference< css::awt::XEventHandler >& handler ) override; + virtual void SAL_CALL removeErrorHandler( const css::uno::Reference< css::awt::XEventHandler >& handler ) override; + virtual css::uno::Any SAL_CALL getIdentifier() override; + +}; + +} + + + +#endif // INCLUDED_VCL_INC_DISPLAYCONNECTIONDISPATCH_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/dndeventdispatcher.hxx b/vcl/inc/dndeventdispatcher.hxx new file mode 100644 index 000000000..bc2f5d999 --- /dev/null +++ b/vcl/inc/dndeventdispatcher.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_DNDEVENTDISPATCHER_HXX +#define INCLUDED_VCL_INC_DNDEVENTDISPATCHER_HXX + +#include +#include + +#include +#include +#include + +class DNDEventDispatcher final : public ::cppu::WeakImplHelper< + css::datatransfer::dnd::XDropTargetListener, + css::datatransfer::dnd::XDropTargetDragContext, + css::datatransfer::dnd::XDragGestureListener > +{ + VclPtr m_pTopWindow; + + VclPtr m_pCurrentWindow; + void designate_currentwindow(vcl::Window *pWindow); + DECL_LINK(WindowEventListener, VclWindowEvent&, void); + + ::osl::Mutex m_aMutex; + css::uno::Sequence< css::datatransfer::DataFlavor > m_aDataFlavorList; + + vcl::Window* findTopLevelWindow(Point location); + /* + * fire the events on the dnd listener container of the specified window + */ + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDragEnterEvent( vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext >& xContext, + const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction, + const css::uno::Sequence< css::datatransfer::DataFlavor >& aFlavorList ); + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDragOverEvent( vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext >& xContext, + const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction ); + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDragExitEvent( vcl::Window *pWindow ); + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDropActionChangedEvent( vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext >& xContext, + const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction ); + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDropEvent( vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext >& xContext, + const sal_Int8 nDropAction, const Point& rLocation, const sal_Int8 nSourceAction, + const css::uno::Reference< css::datatransfer::XTransferable >& xTransferable ); + + /// @throws css::uno::RuntimeException + static sal_Int32 fireDragGestureEvent( vcl::Window *pWindow, const css::uno::Reference< css::datatransfer::dnd::XDragSource >& xSource, + const css::uno::Any& event, const Point& rOrigin, const sal_Int8 nDragAction ); + +public: + + DNDEventDispatcher( vcl::Window * pTopWindow ); + virtual ~DNDEventDispatcher() override; + + /* + * XDropTargetDragContext + */ + + virtual void SAL_CALL acceptDrag( sal_Int8 dropAction ) override; + virtual void SAL_CALL rejectDrag() override; + + /* + * XDropTargetListener + */ + + virtual void SAL_CALL drop( const css::datatransfer::dnd::DropTargetDropEvent& dtde ) override; + virtual void SAL_CALL dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) override; + virtual void SAL_CALL dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) override; + virtual void SAL_CALL dragOver( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override; + virtual void SAL_CALL dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& dtde ) override; + + /* + * XDragGestureListener + */ + + virtual void SAL_CALL dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& dge ) override; + + /* + * XEventListener + */ + + virtual void SAL_CALL disposing( const css::lang::EventObject& eo ) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/dndlistenercontainer.hxx b/vcl/inc/dndlistenercontainer.hxx new file mode 100644 index 000000000..28339e7ab --- /dev/null +++ b/vcl/inc/dndlistenercontainer.hxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_DNDLCON_HXX +#define INCLUDED_VCL_INC_DNDLCON_HXX + +#include +#include +#include +#include +#include +#include + +#include + +class DNDListenerContainer final : public vcl::unohelper::MutexHelper, + public ::cppu::WeakComponentImplHelper< + css::datatransfer::dnd::XDragGestureRecognizer, + css::datatransfer::dnd::XDropTargetDragContext, + css::datatransfer::dnd::XDropTargetDropContext, + css::datatransfer::dnd::XDropTarget > +{ + bool m_bActive; + sal_Int8 m_nDefaultActions; + + css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > m_xDropTargetDragContext; + css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext > m_xDropTargetDropContext; + +public: + + DNDListenerContainer( sal_Int8 nDefaultActions ); + virtual ~DNDListenerContainer() override; + + sal_uInt32 fireDropEvent( + const css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions, + const css::uno::Reference< css::datatransfer::XTransferable >& transferable ); + + sal_uInt32 fireDragExitEvent(); + + sal_uInt32 fireDragOverEvent( + const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions ); + + sal_uInt32 fireDragEnterEvent( + const css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions, + const css::uno::Sequence< css::datatransfer::DataFlavor >& dataFlavor ); + + sal_uInt32 fireDropActionChangedEvent( + const css::uno::Reference< css::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 css::uno::Reference< css::datatransfer::dnd::XDragSource >& dragSource, + const css::uno::Any& triggerEvent ); + + /* + * XDragGestureRecognizer + */ + + virtual void SAL_CALL addDragGestureListener( const css::uno::Reference< css::datatransfer::dnd::XDragGestureListener >& dgl ) override; + virtual void SAL_CALL removeDragGestureListener( const css::uno::Reference< css::datatransfer::dnd::XDragGestureListener >& dgl ) override; + virtual void SAL_CALL resetRecognizer( ) override; + + /* + * XDropTargetDragContext + */ + + virtual void SAL_CALL acceptDrag( sal_Int8 dragOperation ) override; + virtual void SAL_CALL rejectDrag( ) override; + + /* + * XDropTargetDropContext + */ + + virtual void SAL_CALL acceptDrop( sal_Int8 dropOperation ) override; + virtual void SAL_CALL rejectDrop( ) override; + virtual void SAL_CALL dropComplete( sal_Bool success ) override; + + /* + * XDropTarget + */ + + virtual void SAL_CALL addDropTargetListener( const css::uno::Reference< css::datatransfer::dnd::XDropTargetListener >& dtl ) override; + virtual void SAL_CALL removeDropTargetListener( const css::uno::Reference< css::datatransfer::dnd::XDropTargetListener >& dtl ) override; + virtual sal_Bool SAL_CALL isActive( ) override; + virtual void SAL_CALL setActive( sal_Bool active ) override; + virtual sal_Int8 SAL_CALL getDefaultActions( ) override; + virtual void SAL_CALL setDefaultActions( sal_Int8 actions ) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/driverblocklist.hxx b/vcl/inc/driverblocklist.hxx new file mode 100644 index 000000000..c3feea278 --- /dev/null +++ b/vcl/inc/driverblocklist.hxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_DRIVERBLOCKLIST_HXX +#define INCLUDED_VCL_DRIVERBLOCKLIST_HXX + +#include +#include +#include + +namespace DriverBlocklist +{ +// Details of how to treat a version number. +enum class VersionType +{ + OpenGL, // a.b.c.d, 1.98 > 1.978 + Vulkan // a.b.c , 1.98 < 1.978 +}; + +VCL_DLLPUBLIC bool IsDeviceBlocked(const OUString& blocklistURL, VersionType versionType, + const OUString& driverVersion, const OUString& vendorId, + const OUString& deviceId); + +#ifdef _WIN32 +VCL_DLLPUBLIC int32_t GetWindowsVersion(); +#endif + +enum DeviceVendor +{ + VendorAll, + VendorIntel, + VendorNVIDIA, + VendorAMD, + VendorMicrosoft, +}; +const int DeviceVendorMax = VendorMicrosoft + 1; + +/// Returns vendor for the given vendor ID, or VendorAll if not known. +VCL_DLLPUBLIC DeviceVendor GetVendorFromId(uint32_t id); + +VCL_DLLPUBLIC OUStringLiteral GetVendorNameFromId(uint32_t id); + +// The rest should be private (only for the unittest). + +struct InvalidFileException +{ +}; + +enum OperatingSystem +{ + DRIVER_OS_UNKNOWN = 0, + DRIVER_OS_WINDOWS_FIRST, + DRIVER_OS_WINDOWS_7 = DRIVER_OS_WINDOWS_FIRST, + DRIVER_OS_WINDOWS_8, + DRIVER_OS_WINDOWS_8_1, + DRIVER_OS_WINDOWS_10, + DRIVER_OS_WINDOWS_LAST = DRIVER_OS_WINDOWS_10, + DRIVER_OS_WINDOWS_ALL, + DRIVER_OS_LINUX, + DRIVER_OS_OSX_FIRST, + DRIVER_OS_OSX_10_5 = DRIVER_OS_OSX_FIRST, + DRIVER_OS_OSX_10_6, + DRIVER_OS_OSX_10_7, + DRIVER_OS_OSX_10_8, + DRIVER_OS_OSX_LAST = DRIVER_OS_OSX_10_8, + DRIVER_OS_OSX_ALL, + DRIVER_OS_ANDROID, + DRIVER_OS_ALL +}; + +enum VersionComparisonOp +{ + DRIVER_LESS_THAN, // driver < version + DRIVER_LESS_THAN_OR_EQUAL, // driver <= version + DRIVER_GREATER_THAN, // driver > version + DRIVER_GREATER_THAN_OR_EQUAL, // driver >= version + DRIVER_EQUAL, // driver == version + DRIVER_NOT_EQUAL, // driver != version + DRIVER_BETWEEN_EXCLUSIVE, // driver > version && driver < versionMax + DRIVER_BETWEEN_INCLUSIVE, // driver >= version && driver <= versionMax + DRIVER_BETWEEN_INCLUSIVE_START, // driver >= version && driver < versionMax + DRIVER_COMPARISON_IGNORED +}; + +struct DriverInfo +{ + DriverInfo(OperatingSystem os, const OUString& vendor, VersionComparisonOp op, + uint64_t driverVersion, bool bWhiteListed = false, + const char* suggestedVersion = nullptr); + + DriverInfo(); + + OperatingSystem meOperatingSystem; + OUString maAdapterVendor; + std::vector maDevices; + + bool mbWhitelisted; + + VersionComparisonOp meComparisonOp; + + /* versions are assumed to be A.B.C.D packed as 0xAAAABBBBCCCCDDDD */ + uint64_t mnDriverVersion; + uint64_t mnDriverVersionMax; + static uint64_t allDriverVersions; + + OUString maSuggestedVersion; + OUString maMsg; +}; + +class VCL_DLLPUBLIC Parser +{ +public: + Parser(const OUString& rURL, std::vector& rDriverList, VersionType versionType); + bool parse(); + +private: + void handleEntry(DriverInfo& rDriver, xmlreader::XmlReader& rReader); + void handleList(xmlreader::XmlReader& rReader); + void handleContent(xmlreader::XmlReader& rReader); + static void handleDevices(DriverInfo& rDriver, xmlreader::XmlReader& rReader); + uint64_t getVersion(const OString& rString); + + enum class BlockType + { + WHITELIST, + BLACKLIST, + UNKNOWN + }; + + BlockType meBlockType; + std::vector& mrDriverList; + OUString maURL; + const VersionType mVersionType; +}; + +OUString VCL_DLLPUBLIC GetVendorId(DeviceVendor id); + +bool VCL_DLLPUBLIC FindBlocklistedDeviceInList( + std::vector& aDeviceInfos, VersionType versionType, OUString const& sDriverVersion, + OUString const& sAdapterVendorID, OUString const& sAdapterDeviceID, OperatingSystem system, + const OUString& blocklistURL = OUString()); + +#define GFX_DRIVER_VERSION(a, b, c, d) \ + ((uint64_t(a) << 48) | (uint64_t(b) << 32) | (uint64_t(c) << 16) | uint64_t(d)) + +inline uint64_t OpenGLVersion(uint32_t a, uint32_t b, uint32_t c, uint32_t d) +{ + // We make sure every driver number is padded by 0s, this will allow us the + // easiest 'compare as if decimals' approach. See ParseDriverVersion for a + // more extensive explanation of this approach. + while (b > 0 && b < 1000) + { + b *= 10; + } + while (c > 0 && c < 1000) + { + c *= 10; + } + while (d > 0 && d < 1000) + { + d *= 10; + } + return GFX_DRIVER_VERSION(a, b, c, d); +} + +} // namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/factory.hxx b/vcl/inc/factory.hxx new file mode 100644 index 000000000..54a382aa4 --- /dev/null +++ b/vcl/inc/factory.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FACTORY_HXX +#define INCLUDED_VCL_INC_FACTORY_HXX + +#include + +#include +#include +#include + +namespace com::sun::star { + namespace lang { + class XMultiServiceFactory; + class XSingleServiceFactory; + } + namespace uno { class XInterface; } +} + +css::uno::Sequence vcl_session_getSupportedServiceNames(); + +OUString vcl_session_getImplementationName(); + +css::uno::Reference vcl_session_createInstance( + css::uno::Reference const &); + +namespace vcl { + +css::uno::Sequence +FontIdentificator_getSupportedServiceNames(); + +OUString FontIdentificator_getImplementationName(); + +css::uno::Reference +FontIdentificator_createInstance( + css::uno::Reference const &); + +OUString Clipboard_getImplementationName(); + +css::uno::Reference +Clipboard_createFactory(); + +css::uno::Sequence DragSource_getSupportedServiceNames(); + +OUString DragSource_getImplementationName(); + +css::uno::Reference DragSource_createInstance( + css::uno::Reference const &); + +css::uno::Sequence DropTarget_getSupportedServiceNames(); + +OUString DropTarget_getImplementationName(); + +css::uno::Reference DropTarget_createInstance( + css::uno::Reference const &); + +} + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fltcall.hxx b/vcl/inc/fltcall.hxx new file mode 100644 index 000000000..f10e72b07 --- /dev/null +++ b/vcl/inc/fltcall.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_FLTCALL_HXX +#define INCLUDED_VCL_FLTCALL_HXX + +class FilterConfigItem; +class SvStream; +class Graphic; + +typedef bool (*PFilterCall)(SvStream & rStream, Graphic & rGraphic, + FilterConfigItem* pConfigItem); + // Of this type are both export-filter and import-filter functions + // rFileName is the complete path to the file to be imported or exported + // pCallBack can be NULL. pCallerData is handed to the callback function + // pOptionsConfig can be NULL; if not, the group of the config is already set + // and may not be changed by this filter! + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/font/FeatureCollector.hxx b/vcl/inc/font/FeatureCollector.hxx new file mode 100644 index 000000000..bae9e3c56 --- /dev/null +++ b/vcl/inc/font/FeatureCollector.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX +#define INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX + +#include +#include +#include + +namespace vcl +{ +namespace font +{ +class FeatureCollector +{ +private: + hb_face_t* m_pHbFace; + std::vector& m_rFontFeatures; + LanguageType m_eLanguageType; + +public: + FeatureCollector(hb_face_t* pHbFace, std::vector& rFontFeatures, + LanguageType eLanguageType) + : m_pHbFace(pHbFace) + , m_rFontFeatures(rFontFeatures) + , m_eLanguageType(eLanguageType) + { + } + +private: + void collectForLanguage(hb_tag_t aTableTag, sal_uInt32 nScript, hb_tag_t aScriptTag, + sal_uInt32 nLanguage, hb_tag_t aLanguageTag); + + void collectForScript(hb_tag_t aTableTag, sal_uInt32 nScript, hb_tag_t aScriptTag); + void collectForTable(hb_tag_t aTableTag); + bool collectGraphite(); + +public: + bool collect(); +}; + +} // end namespace font +} // end namespace vcl + +#endif // INCLUDED_VCL_INC_FONT_FEATURECOLLECTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx b/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx new file mode 100644 index 000000000..3a01d9135 --- /dev/null +++ b/vcl/inc/font/OpenTypeFeatureDefinitionList.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace vcl +{ +namespace font +{ +class OpenTypeFeatureDefinitionListPrivate +{ +private: + std::vector m_aFeatureDefinition; + std::unordered_map m_aCodeToIndex; + std::vector m_aRequiredFeatures; + + void init(); + + static bool isSpecialFeatureCode(sal_uInt32 nFeatureCode); + static FeatureDefinition handleSpecialFeatureCode(sal_uInt32 nFeatureCode); + +public: + OpenTypeFeatureDefinitionListPrivate(); + FeatureDefinition getDefinition(sal_uInt32 nFeatureCode); + bool isRequired(sal_uInt32 nFeatureCode); +}; + +class VCL_DLLPUBLIC OpenTypeFeatureDefinitionList + : public rtl::Static +{ +}; + +} // end font namespace +} // end vcl namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/font/OpenTypeFeatureStrings.hrc b/vcl/inc/font/OpenTypeFeatureStrings.hrc new file mode 100644 index 000000000..9fa782b16 --- /dev/null +++ b/vcl/inc/font/OpenTypeFeatureStrings.hrc @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONT_OPENTYPEFEATRESTRINGS_HRC +#define INCLUDED_VCL_INC_FONT_OPENTYPEFEATRESTRINGS_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +#define STR_FONT_FEATURE_ID_AALT NC_("STR_FONT_FEATURE_ID_AALT", "Access All Alternates") +#define STR_FONT_FEATURE_ID_AFRC NC_("STR_FONT_FEATURE_ID_AFRC", "Alternative (Vertical) Fractions") +#define STR_FONT_FEATURE_ID_ALIG NC_("STR_FONT_FEATURE_ID_ALIG", "Ancient Ligatures") +#define STR_FONT_FEATURE_ID_C2PC NC_("STR_FONT_FEATURE_ID_C2PC", "Capitals to Petite Capitals") +#define STR_FONT_FEATURE_ID_C2SC NC_("STR_FONT_FEATURE_ID_C2SC", "Capitals to Small Capitals") +#define STR_FONT_FEATURE_ID_CALT NC_("STR_FONT_FEATURE_ID_CALT", "Contextual Alternates") +#define STR_FONT_FEATURE_ID_CASE NC_("STR_FONT_FEATURE_ID_CASE", "Case-Sensitive Forms") +#define STR_FONT_FEATURE_ID_CLIG NC_("STR_FONT_FEATURE_ID_CLIG", "Contextual Ligatures") +#define STR_FONT_FEATURE_ID_CPCT NC_("STR_FONT_FEATURE_ID_CPCT", "Centered CJK Punctuation") +#define STR_FONT_FEATURE_ID_CPSP NC_("STR_FONT_FEATURE_ID_CPSP", "Capital Spacing") +#define STR_FONT_FEATURE_ID_CSWH NC_("STR_FONT_FEATURE_ID_CSWH", "Contextual Swash") +#define STR_FONT_FEATURE_ID_CVXX NC_("STR_FONT_FEATURE_ID_CVXX", "Character Variant %1") +#define STR_FONT_FEATURE_ID_DCAP NC_("STR_FONT_FEATURE_ID_DCAP", "Drop Caps") +#define STR_FONT_FEATURE_ID_DLIG NC_("STR_FONT_FEATURE_ID_DLIG", "Discretionary Ligatures") +#define STR_FONT_FEATURE_ID_DNOM NC_("STR_FONT_FEATURE_ID_DNOM", "Denominators") +#define STR_FONT_FEATURE_ID_DPNG NC_("STR_FONT_FEATURE_ID_DPNG", "Diphthongs (Obsolete)") +#define STR_FONT_FEATURE_ID_EXPT NC_("STR_FONT_FEATURE_ID_EXPT", "Expert Forms") +#define STR_FONT_FEATURE_ID_FALT NC_("STR_FONT_FEATURE_ID_FALT", "Final Glyph on Line Alternates") +#define STR_FONT_FEATURE_ID_FRAC NC_("STR_FONT_FEATURE_ID_FRAC", "Fraction style:") +#define STR_FONT_FEATURE_ID_FRAC_PARAM_0 NC_("STR_FONT_FEATURE_ID_FRAC_PARAM_0", "None") +#define STR_FONT_FEATURE_ID_FRAC_PARAM_1 NC_("STR_FONT_FEATURE_ID_FRAC_PARAM_1", "Diagonal Fractions") +#define STR_FONT_FEATURE_ID_FRAC_PARAM_2 NC_("STR_FONT_FEATURE_ID_FRAC_PARAM_2", "Nut Fractions") +#define STR_FONT_FEATURE_ID_FWID NC_("STR_FONT_FEATURE_ID_FWID", "Full Widths") +#define STR_FONT_FEATURE_ID_HALT NC_("STR_FONT_FEATURE_ID_HALT", "Alternate Half Widths") +#define STR_FONT_FEATURE_ID_HIST NC_("STR_FONT_FEATURE_ID_HIST", "Historical Forms") +#define STR_FONT_FEATURE_ID_HKNA NC_("STR_FONT_FEATURE_ID_HKNA", "Horizontal Kana Alternates") +#define STR_FONT_FEATURE_ID_HLIG NC_("STR_FONT_FEATURE_ID_HLIG", "Historical Ligatures") +#define STR_FONT_FEATURE_ID_HNGL NC_("STR_FONT_FEATURE_ID_HNGL", "Hanja to Hangul (Obsolete)") +#define STR_FONT_FEATURE_ID_HOJO NC_("STR_FONT_FEATURE_ID_HOJO", "Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms)") +#define STR_FONT_FEATURE_ID_HWID NC_("STR_FONT_FEATURE_ID_HWID", "Half Widths") +#define STR_FONT_FEATURE_ID_ITAL NC_("STR_FONT_FEATURE_ID_ITAL", "Italics") +#define STR_FONT_FEATURE_ID_JALT NC_("STR_FONT_FEATURE_ID_JALT", "Justification Alternates") +#define STR_FONT_FEATURE_ID_JP04 NC_("STR_FONT_FEATURE_ID_JP04", "JIS2004 Forms") +#define STR_FONT_FEATURE_ID_JP78 NC_("STR_FONT_FEATURE_ID_JP78", "JIS78 Forms") +#define STR_FONT_FEATURE_ID_JP83 NC_("STR_FONT_FEATURE_ID_JP83", "JIS83 Forms") +#define STR_FONT_FEATURE_ID_JP90 NC_("STR_FONT_FEATURE_ID_JP90", "JIS90 Forms") +#define STR_FONT_FEATURE_ID_KERN NC_("STR_FONT_FEATURE_ID_KERN", "Horizontal Kerning") +#define STR_FONT_FEATURE_ID_LFBD NC_("STR_FONT_FEATURE_ID_LFBD", "Left Bounds") +#define STR_FONT_FEATURE_ID_LIGA NC_("STR_FONT_FEATURE_ID_LIGA", "Standard Ligatures") +#define STR_FONT_FEATURE_ID_LNUM NC_("STR_FONT_FEATURE_ID_LNUM", "Lining Figures") +#define STR_FONT_FEATURE_ID_MGRK NC_("STR_FONT_FEATURE_ID_MGRK", "Mathematical Greek") +#define STR_FONT_FEATURE_ID_NALT NC_("STR_FONT_FEATURE_ID_NALT", "Alternate Annotation Forms") +#define STR_FONT_FEATURE_ID_NLCK NC_("STR_FONT_FEATURE_ID_NLCK", "NLC Kanji Forms") +#define STR_FONT_FEATURE_ID_NUMR NC_("STR_FONT_FEATURE_ID_NUMR", "Numerators") +#define STR_FONT_FEATURE_ID_ONUM NC_("STR_FONT_FEATURE_ID_ONUM", "Oldstyle Figures") +#define STR_FONT_FEATURE_ID_OPBD NC_("STR_FONT_FEATURE_ID_OPBD", "Optical Bounds") +#define STR_FONT_FEATURE_ID_ORDN NC_("STR_FONT_FEATURE_ID_ORDN", "Ordinals") +#define STR_FONT_FEATURE_ID_ORNM NC_("STR_FONT_FEATURE_ID_ORNM", "Ornaments") +#define STR_FONT_FEATURE_ID_PALT NC_("STR_FONT_FEATURE_ID_PALT", "Proportional Alternate Metrics") +#define STR_FONT_FEATURE_ID_PCAP NC_("STR_FONT_FEATURE_ID_PCAP", "Lowercase to Petite Capitals") +#define STR_FONT_FEATURE_ID_PKNA NC_("STR_FONT_FEATURE_ID_PKNA", "Proportional Kana") +#define STR_FONT_FEATURE_ID_PNUM NC_("STR_FONT_FEATURE_ID_PNUM", "Proportional Numbers") +#define STR_FONT_FEATURE_ID_PWID NC_("STR_FONT_FEATURE_ID_PWID", "Proportional Widths") +#define STR_FONT_FEATURE_ID_QWID NC_("STR_FONT_FEATURE_ID_QWID", "Quarter Widths") +#define STR_FONT_FEATURE_ID_RTBD NC_("STR_FONT_FEATURE_ID_RTBD", "Right Bounds") +#define STR_FONT_FEATURE_ID_RUBY NC_("STR_FONT_FEATURE_ID_RUBY", "Ruby Notation Forms") +#define STR_FONT_FEATURE_ID_SALT NC_("STR_FONT_FEATURE_ID_SALT", "Stylistic Alternates") +#define STR_FONT_FEATURE_ID_SINF NC_("STR_FONT_FEATURE_ID_SINF", "Scientific Inferiors") +#define STR_FONT_FEATURE_ID_SMCP NC_("STR_FONT_FEATURE_ID_SMCP", "Lowercase to Small Capitals") +#define STR_FONT_FEATURE_ID_SMPL NC_("STR_FONT_FEATURE_ID_SMPL", "Simplified Forms") +#define STR_FONT_FEATURE_ID_SSXX NC_("STR_FONT_FEATURE_ID_SSXX", "Stylistic Set %1") +#define STR_FONT_FEATURE_ID_SUBS NC_("STR_FONT_FEATURE_ID_SUBS", "Subscript") +#define STR_FONT_FEATURE_ID_SUPS NC_("STR_FONT_FEATURE_ID_SUPS", "Superscript") +#define STR_FONT_FEATURE_ID_SWSH NC_("STR_FONT_FEATURE_ID_SWSH", "Swash") +#define STR_FONT_FEATURE_ID_TITL NC_("STR_FONT_FEATURE_ID_TITL", "Titling") +#define STR_FONT_FEATURE_ID_TNAM NC_("STR_FONT_FEATURE_ID_TNAM", "Traditional Name Forms") +#define STR_FONT_FEATURE_ID_TNUM NC_("STR_FONT_FEATURE_ID_TNUM", "Tabular Numbers") +#define STR_FONT_FEATURE_ID_TRAD NC_("STR_FONT_FEATURE_ID_TRAD", "Traditional Forms") +#define STR_FONT_FEATURE_ID_TWID NC_("STR_FONT_FEATURE_ID_TWID", "Third Widths") +#define STR_FONT_FEATURE_ID_UNIC NC_("STR_FONT_FEATURE_ID_UNIC", "Unicase") +#define STR_FONT_FEATURE_ID_VALT NC_("STR_FONT_FEATURE_ID_VALT", "Alternate Vertical Metrics") +#define STR_FONT_FEATURE_ID_VHAL NC_("STR_FONT_FEATURE_ID_VHAL", "Alternate Vertical Half Metrics") +#define STR_FONT_FEATURE_ID_VKNA NC_("STR_FONT_FEATURE_ID_VKNA", "Vertical Kana Alternates") +#define STR_FONT_FEATURE_ID_VKRN NC_("STR_FONT_FEATURE_ID_VKRN", "Vertical Kerning") +#define STR_FONT_FEATURE_ID_VPAL NC_("STR_FONT_FEATURE_ID_VPAL", "Proportional Alternate Vertical Metrics") +#define STR_FONT_FEATURE_ID_VRT2 NC_("STR_FONT_FEATURE_ID_VRT2", "Vertical Alternates and Rotation") +#define STR_FONT_FEATURE_ID_VRTR NC_("STR_FONT_FEATURE_ID_VRTR", "Vertical Alternates for Rotation") +#define STR_FONT_FEATURE_ID_ZERO NC_("STR_FONT_FEATURE_ID_ZERO", "Slashed Zero") + +#endif // INCLUDED_VCL_INC_STRINGS_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fontattributes.hxx b/vcl/inc/fontattributes.hxx new file mode 100644 index 000000000..352ea10e3 --- /dev/null +++ b/vcl/inc/fontattributes.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONTATTRIBUTES_HXX +#define INCLUDED_VCL_INC_FONTATTRIBUTES_HXX + +#include +#include +#include +#include + + +/* The following class is extraordinarily similar to ImplFont. */ + +class VCL_DLLPUBLIC FontAttributes +{ +public: + explicit FontAttributes(); + + // device independent font functions + const OUString& GetFamilyName() const { return maFamilyName; } + FontFamily GetFamilyType() const { return meFamily; } + const OUString& GetStyleName() const { return maStyleName; } + + FontWeight GetWeight() const { return meWeight; } + FontItalic GetItalic() const { return meItalic; } + FontPitch GetPitch() const { return mePitch; } + FontWidth GetWidthType() const { return meWidthType; } + rtl_TextEncoding GetCharSet() const { return meCharSet; } + + bool IsSymbolFont() const { return mbSymbolFlag; } + + void SetFamilyName(const OUString& sFamilyName) { maFamilyName = sFamilyName; } + void SetStyleName( const OUString& sStyleName) { maStyleName = sStyleName; } + void SetFamilyType(const FontFamily eFontFamily) { meFamily = eFontFamily; } + + void SetPitch(const FontPitch ePitch ) { mePitch = ePitch; } + void SetItalic(const FontItalic eItalic ) { meItalic = eItalic; } + void SetWeight(const FontWeight eWeight ) { meWeight = eWeight; } + void SetWidthType(const FontWidth eWidthType) { meWidthType = eWidthType; } + + void SetSymbolFlag(const bool ); + + bool CompareDeviceIndependentFontAttributes(const FontAttributes& rOther) const; + + // Device dependent functions + int GetQuality() const { return mnQuality; } + const OUString& GetMapNames() const { return maMapNames; } + + + void SetQuality( int nQuality ) { mnQuality = nQuality; } + void IncreaseQualityBy( int nQualityAmount ) { mnQuality += nQualityAmount; } + void AddMapName( OUString const& ); + +private: + // device independent variables + OUString maFamilyName; // Font Family Name + OUString maStyleName; // Font Style Name + FontWeight meWeight; // Weight Type + FontFamily meFamily; // Family Type + FontPitch mePitch; // Pitch Type + FontWidth meWidthType; // Width Type + FontItalic meItalic; // Slant Type + rtl_TextEncoding meCharSet; // RTL_TEXTENCODING_SYMBOL or RTL_TEXTENCODING_UNICODE + bool mbSymbolFlag; // Is font a symbol? + + // device dependent variables + OUString maMapNames; // List of family name aliases separated with ';' + int mnQuality; // Quality (used when similar fonts compete) + +}; + +inline void FontAttributes::SetSymbolFlag( const bool bSymbolFlag ) +{ + mbSymbolFlag = bSymbolFlag; + if ( bSymbolFlag ) + { + meCharSet = RTL_TEXTENCODING_SYMBOL; + } + else + { + // if the symbol flag is unset, but it was a symbol font before then + // until the character set encoding is set via SetCharSet then we + // can't know what the characterset is! + if ( meCharSet == RTL_TEXTENCODING_SYMBOL ) + { + meCharSet = RTL_TEXTENCODING_DONTKNOW; + } + } +} + +inline void FontAttributes::AddMapName( OUString const & aMapName ) +{ + if( maMapNames.getLength() > 0 ) + { + maMapNames += ";"; + } + + if (aMapName.getLength() == 0) + { + SAL_WARN("vcl.fonts", "New map name is empty"); + return; + } + + maMapNames += aMapName; +} + +#endif // INCLUDED_VCL_INC_FONTATTRIBUTES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fontinstance.hxx b/vcl/inc/fontinstance.hxx new file mode 100644 index 000000000..4aff50c95 --- /dev/null +++ b/vcl/inc/fontinstance.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONTINSTANCE_HXX +#define INCLUDED_VCL_INC_FONTINSTANCE_HXX + +#include "fontselect.hxx" +#include "impfontmetricdata.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +class ConvertChar; +class ImplFontCache; +class PhysicalFontFace; + +// TODO: allow sharing of metrics for related fonts + +class VCL_PLUGIN_PUBLIC LogicalFontInstance : public salhelper::SimpleReferenceObject +{ + // just declaring the factory function doesn't work AKA + // friend LogicalFontInstance* PhysicalFontFace::CreateFontInstance(const FontSelectPattern&) const; + friend class PhysicalFontFace; + friend class ImplFontCache; + +public: // TODO: make data members private + virtual ~LogicalFontInstance() override; + + ImplFontMetricDataRef mxFontMetric; // Font attributes + const ConvertChar* mpConversion; // used e.g. for StarBats->StarSymbol + + long mnLineHeight; + short mnOwnOrientation; // text angle if lower layers don't rotate text themselves + short mnOrientation; // text angle in 3600 system + bool mbInit; // true if maFontMetric member is valid + + void AddFallbackForUnicode( sal_UCS4, FontWeight eWeight, const OUString& rFontName ); + bool GetFallbackForUnicode( sal_UCS4, FontWeight eWeight, OUString* pFontName ) const; + void IgnoreFallbackForUnicode( sal_UCS4, FontWeight eWeight, const OUString& rFontName ); + + inline hb_font_t* GetHbFont(); + bool IsGraphiteFont(); + void SetAverageWidthFactor(double nFactor) { m_nAveWidthFactor = std::abs(nFactor); } + double GetAverageWidthFactor() const { return m_nAveWidthFactor; } + const FontSelectPattern& GetFontSelectPattern() const { return m_aFontSelData; } + + const PhysicalFontFace* GetFontFace() const { return m_pFontFace.get(); } + PhysicalFontFace* GetFontFace() { return m_pFontFace.get(); } + const ImplFontCache* GetFontCache() const { return mpFontCache; } + + bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const; + virtual bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const = 0; + + int GetKashidaWidth(); + + void GetScale(double* nXScale, double* nYScale); + static inline void DecodeOpenTypeTag(const uint32_t nTableTag, char* pTagName); + +protected: + explicit LogicalFontInstance(const PhysicalFontFace&, const FontSelectPattern&); + + virtual bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const = 0; + + // Takes ownership of pHbFace. + static hb_font_t* InitHbFont(hb_face_t* pHbFace); + virtual hb_font_t* ImplInitHbFont() { assert(false); return hb_font_get_empty(); } + +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::unordered_map< ::std::pair, OUString > UnicodeFallbackList; + std::unique_ptr mpUnicodeFallbackList; + mutable ImplFontCache * mpFontCache; + const FontSelectPattern m_aFontSelData; + hb_font_t* m_pHbFont; + double m_nAveWidthFactor; + rtl::Reference m_pFontFace; + std::optional m_xbIsGraphiteFont; +}; + +inline hb_font_t* LogicalFontInstance::GetHbFont() +{ + if (!m_pHbFont) + m_pHbFont = ImplInitHbFont(); + return m_pHbFont; +} + +inline void LogicalFontInstance::DecodeOpenTypeTag(const uint32_t nTableTag, char* pTagName) +{ + pTagName[0] = static_cast(nTableTag >> 24); + pTagName[1] = static_cast(nTableTag >> 16); + pTagName[2] = static_cast(nTableTag >> 8); + pTagName[3] = static_cast(nTableTag); + pTagName[4] = 0; +} + +#endif // INCLUDED_VCL_INC_FONTINSTANCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fontselect.hxx b/vcl/inc/fontselect.hxx new file mode 100644 index 000000000..7df7dd930 --- /dev/null +++ b/vcl/inc/fontselect.hxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONTSELECT_HXX +#define INCLUDED_VCL_INC_FONTSELECT_HXX + +#include +#include + +#include "fontattributes.hxx" + +#include + +namespace vcl { class Font; } + +class LogicalFontInstance; +class PhysicalFontFace; +class Size; + +class VCL_DLLPUBLIC FontSelectPattern : public FontAttributes +{ +public: + FontSelectPattern(const vcl::Font&, const OUString& rSearchName, + const Size&, float fExactHeight, bool bNonAntialias = false); +#ifdef _WIN32 + FontSelectPattern( const PhysicalFontFace&, const Size&, + float fExactHeight, int nOrientation, bool bVertical ); +#endif + + size_t hashCode() const; + bool operator==(const FontSelectPattern& rOther) const; + bool operator!=(const FontSelectPattern& rOther) const + { + return !(*this == rOther); + } + + static const char FEAT_PREFIX; + static const char FEAT_SEPARATOR; + +public: + OUString maTargetName; // name of the font name token that is chosen + OUString 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 1/10 degree (0-3600) + LanguageType meLanguage; // text language + bool mbVertical; // vertical mode of requested font + bool mbNonAntialiased; // true if antialiasing is disabled + + bool mbEmbolden; // Force emboldening + ItalicMatrix maItalicMatrix; // Force matrix for slant +}; + +template< typename charT, typename traits > +inline std::basic_ostream & operator <<( + std::basic_ostream & stream, const FontSelectPattern & rFSP) +{ + stream << (rFSP.maTargetName.isEmpty() ? "" : rFSP.maTargetName) + << " (" << rFSP.maSearchName << ") w: " << rFSP.mnWidth << " h: " + << rFSP.mnHeight << " alias: " << rFSP.mbNonAntialiased; + return stream; +} + +#endif // INCLUDED_VCL_INC_FONTSELECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/fontsubset.hxx b/vcl/inc/fontsubset.hxx new file mode 100644 index 000000000..54fa20946 --- /dev/null +++ b/vcl/inc/fontsubset.hxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONTSUBSET_HXX +#define INCLUDED_VCL_INC_FONTSUBSET_HXX + +#include +#include +#include + +#include +#include + +namespace vcl { struct TrueTypeFont; } ///< SFT's idea of a TTF font + +enum class 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 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +class VCL_DLLPUBLIC FontSubsetInfo final +{ +public: + explicit FontSubsetInfo(); + ~FontSubsetInfo(); + + void LoadFont( FontType eInFontType, + const unsigned char* pFontBytes, int nByteLength ); + void LoadFont( vcl::TrueTypeFont* pSftTrueTypeFont ); + + bool CreateFontSubset( FontType nOutFontTypeMask, + FILE* pOutFile, const char* pOutFontName, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncodedIds, + int nReqGlyphCount, sal_Int32* pOutGlyphWidths = nullptr ); + +public: // TODO: make subsetter results private and provide accessor methods instead + // subsetter-provided subset details needed by e.g. Postscript or PDF + OUString m_aPSName; + int m_nAscent; ///< all metrics in PS font units + int m_nDescent; + int m_nCapHeight; + tools::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 + FontType mnReqFontTypeMask; ///< allowed subset-target font types + FILE* mpOutFile; + const char* mpReqFontName; + const sal_GlyphId* mpReqGlyphIds; + const sal_uInt8* mpReqEncodedIds; + int mnReqGlyphCount; + + bool CreateFontSubsetFromCff( sal_Int32* pOutGlyphWidths ); + bool CreateFontSubsetFromSfnt( sal_Int32* pOutGlyphWidths ); + static bool CreateFontSubsetFromType1( const sal_Int32* pOutGlyphWidths ); +}; + +#endif // INCLUDED_VCL_INC_FONTSUBSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/DetectorTools.hxx b/vcl/inc/graphic/DetectorTools.hxx new file mode 100644 index 000000000..3847457fc --- /dev/null +++ b/vcl/inc/graphic/DetectorTools.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +namespace vcl +{ +const char* matchArray(const char* pSource, sal_Int32 nSourceSize, const char* pSearch, + sal_Int32 nSearchSize) +{ + for (sal_Int32 increment = 0; increment <= (nSourceSize - nSearchSize); ++increment) + { + bool bMatch = true; + // search both arrays if they match + for (sal_Int32 index = 0; index < nSearchSize && bMatch; ++index) + { + if (pSource[index] != pSearch[index]) + bMatch = false; + } + // match has been found + if (bMatch) + return pSource; + pSource++; + } + return nullptr; +} + +const char* matchArrayWithString(const char* pSource, sal_Int32 nSourceSize, OString const& rString) +{ + return matchArray(pSource, nSourceSize, rString.getStr(), rString.getLength()); +} + +bool checkArrayForMatchingStrings(const char* pSource, sal_Int32 nSourceSize, + std::vector const& rStrings) +{ + if (rStrings.empty()) + return false; + if (rStrings.size() < 2) + return matchArrayWithString(pSource, nSourceSize, rStrings[0]) != nullptr; + + const char* pBegin = pSource; + const char* pCurrent = pSource; + for (OString const& rString : rStrings) + { + sal_Int32 nCurrentSize = nSourceSize - sal_Int32(pCurrent - pBegin); + pCurrent = matchArray(pCurrent, nCurrentSize, rString.getStr(), rString.getLength()); + if (pCurrent == nullptr) + return false; + } + return true; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/GraphicFormatDetector.hxx b/vcl/inc/graphic/GraphicFormatDetector.hxx new file mode 100644 index 000000000..e914ee64a --- /dev/null +++ b/vcl/inc/graphic/GraphicFormatDetector.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GRAPHICFORMATDETECTOR_HXX +#define INCLUDED_VCL_INC_GRAPHICFORMATDETECTOR_HXX + +#include +#include + +VCL_DLLPUBLIC bool ImpPeekGraphicFormat(SvStream& rStream, OUString& rFormatExtension, bool bTest); + +namespace vcl +{ +class VCL_DLLPUBLIC GraphicFormatDetector +{ +public: + SvStream& mrStream; + OUString maExtension; + + std::vector maFirstBytes; + sal_uInt32 mnFirstLong; + sal_uInt32 mnSecondLong; + + sal_uInt64 mnStreamPosition; + sal_uInt64 mnStreamLength; + + OUString msDetectedFormat; + + GraphicFormatDetector(SvStream& rStream, OUString const& rFormatExtension); + + bool detect(); + + bool checkMET(); + bool checkBMP(); + bool checkWMForEMF(); + bool checkPCX(); + bool checkTIF(); + bool checkGIF(); + bool checkPNG(); + bool checkJPG(); + bool checkSVM(); + bool checkPCD(); + bool checkPSD(); + bool checkEPS(); + bool checkDXF(); + bool checkPCT(); + bool checkPBMorPGMorPPM(); + bool checkRAS(); + bool checkXPM(); + bool checkXBM(); + bool checkSVG(); + bool checkTGA(); + bool checkMOV(); + bool checkPDF(); +}; +} + +#endif // INCLUDED_VCL_INC_GRAPHICFORMATDETECTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/GraphicID.hxx b/vcl/inc/graphic/GraphicID.hxx new file mode 100644 index 000000000..87ac6a50f --- /dev/null +++ b/vcl/inc/graphic/GraphicID.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +class ImpGraphic; + +class GraphicID +{ +private: + sal_uInt32 mnID1; + sal_uInt32 mnID2; + sal_uInt32 mnID3; + BitmapChecksum mnID4; + +public: + GraphicID(ImpGraphic const& rGraphic); + + bool operator==(const GraphicID& rID) const + { + return rID.mnID1 == mnID1 && rID.mnID2 == mnID2 && rID.mnID3 == mnID3 && rID.mnID4 == mnID4; + } + + OString getIDString() const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/GraphicReader.hxx b/vcl/inc/graphic/GraphicReader.hxx new file mode 100644 index 000000000..9576d4253 --- /dev/null +++ b/vcl/inc/graphic/GraphicReader.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +class GraphicReader +{ +public: + virtual ~GraphicReader(); + + const OUString& GetUpperFilterName() const { return maUpperName; } + +protected: + OUString maUpperName; + + GraphicReader(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/Manager.hxx b/vcl/inc/graphic/Manager.hxx new file mode 100644 index 000000000..bb52a0cfc --- /dev/null +++ b/vcl/inc/graphic/Manager.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_GRAPHIC_MANAGER_HXX +#define INCLUDED_VCL_INC_GRAPHIC_MANAGER_HXX + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +class ImpGraphic; + +namespace vcl +{ +namespace graphic +{ +class Manager final +{ +private: + std::recursive_mutex maMutex; // instead of SolarMutex because graphics can live past vcl main + o3tl::sorted_vector m_pImpGraphicList; + std::chrono::seconds mnAllowedIdleTime; + bool mbSwapEnabled; + sal_Int64 mnMemoryLimit; + sal_Int64 mnUsedSize; + Timer maSwapOutTimer; + + Manager(); + + void registerGraphic(const std::shared_ptr& rImpGraphic, OUString const& rsContext); + + DECL_LINK(SwapOutTimerHandler, Timer*, void); + + static sal_Int64 getGraphicSizeBytes(const ImpGraphic* pImpGraphic); + +public: + static Manager& get(); + + void swappedIn(const ImpGraphic* pImpGraphic); + void swappedOut(const ImpGraphic* pImpGraphic); + + void reduceGraphicMemory(); + void changeExisting(const ImpGraphic* pImpGraphic, sal_Int64 nOldSize); + void unregisterGraphic(ImpGraphic* pImpGraphic); + + std::shared_ptr copy(std::shared_ptr const& pImpGraphic); + std::shared_ptr newInstance(); + std::shared_ptr newInstance(const Bitmap& rBitmap); + std::shared_ptr newInstance(const BitmapEx& rBitmapEx); + std::shared_ptr + newInstance(const std::shared_ptr& rVectorGraphicDataPtr); + std::shared_ptr newInstance(const Animation& rAnimation); + std::shared_ptr newInstance(const GDIMetaFile& rMtf); + std::shared_ptr newInstance(const GraphicExternalLink& rGraphicLink); +}; +} +} // end namespace vcl::graphic + +#endif // INCLUDED_VCL_INC_GRAPHIC_MANAGER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/UnoGraphic.hxx b/vcl/inc/graphic/UnoGraphic.hxx new file mode 100644 index 000000000..f6eed8fab --- /dev/null +++ b/vcl/inc/graphic/UnoGraphic.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SOURCE_GRAPHIC_GRAPHIC_HXX +#define INCLUDED_VCL_SOURCE_GRAPHIC_GRAPHIC_HXX + +#include +#include +#include + +#include +#include + +#include + +namespace unographic { + +class Graphic final : public css::graphic::XGraphic, + public css::awt::XBitmap, + public css::lang::XUnoTunnel, + public ::unographic::GraphicDescriptor, + public ::unographic::GraphicTransformer +{ +public: + Graphic(); + virtual ~Graphic() throw() override; + + using ::unographic::GraphicDescriptor::init; + void init( const ::Graphic& rGraphic ) throw(); + +private: + + // XInterface + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type & rType ) override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // XGraphic + virtual ::sal_Int8 SAL_CALL getType( ) override; + + // XBitmap + virtual css::awt::Size SAL_CALL getSize( ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getDIB( ) override; + virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getMaskDIB( ) override; + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& rId ) override; + + ::Graphic maGraphic; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/UnoGraphicDescriptor.hxx b/vcl/inc/graphic/UnoGraphicDescriptor.hxx new file mode 100644 index 000000000..ad46952ce --- /dev/null +++ b/vcl/inc/graphic/UnoGraphicDescriptor.hxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SOURCE_GRAPHIC_DESCRIPTOR_HXX +#define INCLUDED_VCL_SOURCE_GRAPHIC_DESCRIPTOR_HXX + +#include +#include + +#include +#include +#include + +#define MIMETYPE_BMP "image/x-MS-bmp" +#define MIMETYPE_GIF "image/gif" +#define MIMETYPE_JPG "image/jpeg" +#define MIMETYPE_PCD "image/x-photo-cd" +#define MIMETYPE_PCX "image/x-pcx" +#define MIMETYPE_PNG "image/png" +#define MIMETYPE_TIF "image/tiff" +#define MIMETYPE_XBM "image/x-xbitmap" +#define MIMETYPE_XPM "image/x-xpixmap" +#define MIMETYPE_PBM "image/x-portable-bitmap" +#define MIMETYPE_PGM "image/x-portable-graymap" +#define MIMETYPE_PPM "image/x-portable-pixmap" +#define MIMETYPE_RAS "image/x-cmu-raster" +#define MIMETYPE_TGA "image/x-targa" +#define MIMETYPE_PSD "image/vnd.adobe.photoshop" +#define MIMETYPE_EPS "image/x-eps" +#define MIMETYPE_DXF "image/vnd.dxf" +#define MIMETYPE_MET "image/x-met" +#define MIMETYPE_PCT "image/x-pict" +#define MIMETYPE_SVM "image/x-svm" +#define MIMETYPE_WMF "image/x-wmf" +#define MIMETYPE_EMF "image/x-emf" +#define MIMETYPE_SVG "image/svg+xml" +#define MIMETYPE_PDF "application/pdf" +#define MIMETYPE_VCLGRAPHIC "image/x-vclgraphic" + +namespace comphelper { class PropertySetInfo; } +namespace com::sun::star::io { class XInputStream; } + +class Graphic; + +namespace unographic { + +class GraphicDescriptor : public ::cppu::OWeakAggObject, + public css::lang::XServiceInfo, + public css::lang::XTypeProvider, + public ::comphelper::PropertySetHelper +{ +public: + + GraphicDescriptor(); + virtual ~GraphicDescriptor() throw() override; + + void init( const ::Graphic& rGraphic ); + void init( const OUString& rURL ); + void init( const css::uno::Reference< css::io::XInputStream >& rxIStm, const OUString& rURL ); + +protected: + + static rtl::Reference<::comphelper::PropertySetInfo> createPropertySetInfo(); + + // XInterface + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type & rType ) override; + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // PropertySetHelper + virtual void _setPropertyValues( const comphelper::PropertyMapEntry** ppEntries, const css::uno::Any* pValues ) override; + virtual void _getPropertyValues( const comphelper::PropertyMapEntry** ppEntries, css::uno::Any* pValue ) override; + +private: + + const ::Graphic* mpGraphic; + GraphicType meType; + OUString maMimeType; + Size maSizePixel; + Size maSize100thMM; + sal_uInt16 mnBitsPerPixel; + bool mbTransparent; + + GraphicDescriptor( const GraphicDescriptor& rDescriptor ) = delete; + + GraphicDescriptor& operator=( const GraphicDescriptor& ) = delete; + + void implCreate( SvStream& rIStm, const OUString* pPath ); +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/graphic/UnoGraphicTransformer.hxx b/vcl/inc/graphic/UnoGraphicTransformer.hxx new file mode 100644 index 000000000..785efdcd1 --- /dev/null +++ b/vcl/inc/graphic/UnoGraphicTransformer.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SOURCE_GRAPHIC_TRANSFORMER_HXX +#define INCLUDED_VCL_SOURCE_GRAPHIC_TRANSFORMER_HXX + +#include +#include + +namespace unographic { + + +typedef ::cppu::WeakAggImplHelper1< + css::graphic::XGraphicTransformer + > GraphicTransformer_UnoImplHelper1; +class GraphicTransformer : public GraphicTransformer_UnoImplHelper1 +{ + public: + + GraphicTransformer(); + virtual ~GraphicTransformer() override; + + // XGraphicTransformer + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL colorChange( + const css::uno::Reference< css::graphic::XGraphic >& rGraphic, + sal_Int32 nColorFrom, sal_Int8 nTolerance, sal_Int32 nColorTo, sal_Int8 nAlphaTo ) override; + + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL applyDuotone( + const css::uno::Reference< css::graphic::XGraphic >& rGraphic, + sal_Int32 nColorOne, sal_Int32 nColorTwo ) override; + + virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL applyBrightnessContrast( + const css::uno::Reference< css::graphic::XGraphic >& rxGraphic, + sal_Int32 nBrightness, sal_Int32 nContrast, sal_Bool mso ) override; + +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/CustomWidgetDraw.hxx b/vcl/inc/headless/CustomWidgetDraw.hxx new file mode 100644 index 000000000..f30488ca8 --- /dev/null +++ b/vcl/inc/headless/CustomWidgetDraw.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_CUSTOMWIDGETDRAW_HXX +#define INCLUDED_VCL_INC_CUSTOMWIDGETDRAW_HXX + +#include +#include +#include +#include +#include + +namespace vcl +{ +class CustomWidgetDraw final : public vcl::WidgetDrawInterface +{ +private: + static WidgetThemeLibrary* s_pWidgetImplementation; + SvpSalGraphics& m_rGraphics; + +public: + CustomWidgetDraw(SvpSalGraphics& rGraphics); + ~CustomWidgetDraw() override; + + bool isNativeControlSupported(ControlType eType, ControlPart ePart) override; + + bool hitTestNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, const Point& aPos, + bool& rIsInside) override; + + bool drawNativeControl(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, ControlState eState, + const ImplControlValue& aValue, const OUString& aCaptions, + const Color& rBackgroundColor) override; + + bool getNativeControlRegion(ControlType eType, ControlPart ePart, + const tools::Rectangle& rBoundingControlRegion, ControlState eState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle& rNativeBoundingRegion, + tools::Rectangle& rNativeContentRegion) override; + + bool updateSettings(AllSettings& rSettings) override; +}; + +} // end vcl namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpbmp.hxx b/vcl/inc/headless/svpbmp.hxx new file mode 100644 index 000000000..1551fc844 --- /dev/null +++ b/vcl/inc/headless/svpbmp.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPBMP_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPBMP_HXX + +#include + +#include +#include + +class VCL_DLLPUBLIC SvpSalBitmap final : public SalBitmap, public basegfx::SystemDependentDataHolder // MM02 +{ + std::unique_ptr mpDIB; +public: + SvpSalBitmap(); + virtual ~SvpSalBitmap() override; + + // SalBitmap + virtual bool Create( const Size& rSize, + sal_uInt16 nBitCount, + const BitmapPalette& rPal ) override; + virtual bool Create( const SalBitmap& rSalBmp ) override; + virtual bool Create( const SalBitmap& rSalBmp, + SalGraphics* pGraphics ) override; + virtual bool Create( const SalBitmap& rSalBmp, + sal_uInt16 nNewBitCount ) override; + virtual bool Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false ) override; + void Create(std::unique_ptr pBuf); + const BitmapBuffer* GetBuffer() const + { + return mpDIB.get(); + } + virtual void Destroy() final override; + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override; + virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override; + virtual bool GetSystemData( BitmapSystemData& rData ) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) override; + virtual bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) override; + + // MM02 exclusive management op's for SystemDependentData at WinSalBitmap + template + std::shared_ptr getSystemDependentData() const + { + return std::static_pointer_cast(basegfx::SystemDependentDataHolder::getSystemDependentData(typeid(T).hash_code())); + } + + template + std::shared_ptr addOrReplaceSystemDependentData(basegfx::SystemDependentDataManager& manager, Args&&... args) const + { + std::shared_ptr r = std::make_shared(manager, std::forward(args)...); + + // tdf#129845 only add to buffer if a relevant buffer time is estimated + if(r->calculateCombinedHoldCyclesInSeconds() > 0) + { + basegfx::SystemDependentData_SharedPtr r2(r); + const_cast< SvpSalBitmap* >(this)->basegfx::SystemDependentDataHolder::addOrReplaceSystemDependentData(r2); + } + + return r; + } +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPBMP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpcairotextrender.hxx b/vcl/inc/headless/svpcairotextrender.hxx new file mode 100644 index 000000000..35744d5a2 --- /dev/null +++ b/vcl/inc/headless/svpcairotextrender.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_GTK3_GDI_GTK3CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_UNX_GTK3_GDI_GTK3CAIROTEXTRENDER_HXX + +#include + +class SvpSalGraphics; + +class SvpCairoTextRender final : public CairoTextRender +{ + SvpSalGraphics& mrParent; + +public: + explicit SvpCairoTextRender(SvpSalGraphics& rParent); + + virtual cairo_t* getCairoContext() override; + virtual void getSurfaceOffset(double& nDX, double& nDY) override; + virtual void clipRegion(cairo_t* cr) override; + virtual void releaseCairoContext(cairo_t* cr) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpdummies.hxx b/vcl/inc/headless/svpdummies.hxx new file mode 100644 index 000000000..51007916b --- /dev/null +++ b/vcl/inc/headless/svpdummies.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPDUMMIES_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPDUMMIES_HXX + +#include +#include +#include + +class SalGraphics; + +class SvpSalObject final : public SalObject +{ +public: + SystemEnvData m_aSystemChildData; + + virtual ~SvpSalObject() override; + + // override all pure virtual methods + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + + virtual const SystemEnvData* GetSystemData() const override; +}; + +class SvpSalSystem : public SalGenericSystem +{ +public: + SvpSalSystem() {} + virtual ~SvpSalSystem() override; + // get info about the display + virtual unsigned int GetDisplayScreenCount() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ) override; + + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) override; +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPDUMMIES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpframe.hxx b/vcl/inc/headless/svpframe.hxx new file mode 100644 index 000000000..7245a31d5 --- /dev/null +++ b/vcl/inc/headless/svpframe.hxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPFRAME_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPFRAME_HXX + +#include + +#include + +#include +#include + +#ifdef IOS +#define SvpSalInstance AquaSalInstance +#define SvpSalGraphics AquaSalGraphics +#endif + +class SvpSalInstance; +class SvpSalGraphics; + +class SvpSalFrame : public SalFrame +{ + SvpSalInstance* m_pInstance; + SvpSalFrame* m_pParent; // pointer to parent frame + std::list< SvpSalFrame* > m_aChildren; // List of child frames + SalFrameStyleFlags m_nStyle; + bool m_bVisible; +#ifndef IOS + cairo_surface_t* m_pSurface; +#endif + long m_nMinWidth; + long m_nMinHeight; + long m_nMaxWidth; + long m_nMaxHeight; + + SystemEnvData m_aSystemChildData; + + std::vector< SvpSalGraphics* > m_aGraphics; + + static SvpSalFrame* s_pFocusFrame; +public: + SvpSalFrame( SvpSalInstance* pInstance, + SalFrame* pParent, + SalFrameStyleFlags nSalFrameStyle ); + virtual ~SvpSalFrame() override; + + void GetFocus(); + void LoseFocus(); + void PostPaint() const; + + // SalFrame + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + virtual bool PostEvent(std::unique_ptr pData) override; + + virtual void SetTitle( const OUString& rTitle ) override; + virtual void SetIcon( sal_uInt16 nIcon ) override; + virtual void SetMenu( SalMenu* pMenu ) override; + virtual void DrawMenuBar() override; + + virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ) override; + virtual void Show( bool bVisible, bool bNoActivate = false ) override; + virtual void SetMinClientSize( long nWidth, long nHeight ) override; + virtual void SetMaxClientSize( long nWidth, long nHeight ) override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) override; + virtual void GetClientSize( long& rWidth, long& rHeight ) override; + virtual void GetWorkArea( tools::Rectangle& rRect ) override; + virtual SalFrame* GetParent() const override; + virtual void SetWindowState( const SalFrameState* pState ) override; + virtual bool GetWindowState( SalFrameState* pState ) override; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) override; + virtual void StartPresentation( bool bStart ) override; + virtual void SetAlwaysOnTop( bool bOnTop ) override; + virtual void ToTop( SalFrameToTop nFlags ) override; + virtual void SetPointer( PointerStyle ePointerStyle ) override; + virtual void CaptureMouse( bool bMouse ) override; + virtual void SetPointerPos( long nX, long nY ) override; + using SalFrame::Flush; + virtual void Flush() override; + virtual void SetInputContext( SalInputContext* pContext ) override; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) override; + virtual OUString GetKeyName( sal_uInt16 nKeyCode ) override; + virtual bool MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode ) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings( AllSettings& rSettings ) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override; + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) override; + virtual void SetParent( SalFrame* pNewParent ) override; + virtual bool SetPluginParent( SystemParentData* pNewParent ) override; + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + virtual void EndSetClipRegion() override; + + /*TODO: functional implementation */ + virtual void SetScreenNumber( unsigned int ) override {} + virtual void SetApplicationID(const OUString &) override {} + +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPFRAME_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx new file mode 100644 index 000000000..3d1617d07 --- /dev/null +++ b/vcl/inc/headless/svpgdi.hxx @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPGDI_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPGDI_HXX + +#ifdef IOS +#error This file is not for iOS +#endif + +#include + +#include +#include +#include + +#include +#include +#include "svpcairotextrender.hxx" +#include + +#include + +//Using formats that match cairo's formats. For android we patch cairo, +//which is internal in that case, to swap the rgb components so that +//cairo then matches the OpenGL GL_RGBA format so we can use it there +//where we don't have GL_BGRA support. +// SVP_24BIT_FORMAT is used to store 24-bit images in 3-byte pixels to conserve memory. +#if defined(ANDROID) && !HAVE_FEATURE_ANDROID_LOK +# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown) +# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgba | ScanlineFormat::TopDown) +# define SVP_CAIRO_BLUE 1 +# define SVP_CAIRO_GREEN 2 +# define SVP_CAIRO_RED 0 +# define SVP_CAIRO_ALPHA 3 +#elif defined OSL_BIGENDIAN +# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown) +# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown) +# define SVP_CAIRO_BLUE 3 +# define SVP_CAIRO_GREEN 2 +# define SVP_CAIRO_RED 1 +# define SVP_CAIRO_ALPHA 0 +#else +# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcBgr | ScanlineFormat::TopDown) +# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown) +# define SVP_CAIRO_BLUE 0 +# define SVP_CAIRO_GREEN 1 +# define SVP_CAIRO_RED 2 +# define SVP_CAIRO_ALPHA 3 +#endif + +struct BitmapBuffer; +class FreetypeFont; +typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; +typedef struct _cairo_user_data_key cairo_user_data_key_t; + +VCL_DLLPUBLIC void dl_cairo_surface_set_device_scale(cairo_surface_t *surface, double x_scale, double y_scale); +VCL_DLLPUBLIC void dl_cairo_surface_get_device_scale(cairo_surface_t *surface, double *x_scale, double *y_scale); + +enum class PaintMode { Over, Xor }; + +typedef void (*damageHandler)(void* handle, + sal_Int32 nExtentsX, sal_Int32 nExtentsY, + sal_Int32 nExtentsWidth, sal_Int32 nExtentsHeight); + +struct VCL_DLLPUBLIC DamageHandler +{ + void *handle; + damageHandler damaged; +}; + +class VCL_DLLPUBLIC SvpSalGraphics : public SalGraphics +{ + cairo_surface_t* m_pSurface; + basegfx::B2IVector m_aFrameSize; + double m_fScale; + Color m_aLineColor; + Color m_aFillColor; + PaintMode m_ePaintMode; + +public: + void setSurface(cairo_surface_t* pSurface, const basegfx::B2IVector& rSize); + cairo_surface_t* getSurface() const { return m_pSurface; } + static cairo_user_data_key_t* getDamageKey(); + + static void clipRegion(cairo_t* cr, const vcl::Region& rClipRegion); + + // need this static version of ::drawPolyLine for usage from + // vcl/unx/generic/gdi/salgdi.cxx. It gets wrapped by + // ::drawPolyLine with some added parameters (see there) + static bool drawPolyLine( + cairo_t* cr, + basegfx::B2DRange* pExtents, + const Color& rLineColor, + bool bAntiAliasB2DDraw, + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline); + + void copySource(const SalTwoRect& rTR, cairo_surface_t* source); + void copyWithOperator(const SalTwoRect& rTR, cairo_surface_t* source, + cairo_operator_t eOp = CAIRO_OPERATOR_SOURCE); + +private: + void invert(const basegfx::B2DPolygon &rPoly, SalInvert nFlags); + void applyColor(cairo_t *cr, Color rColor, double fTransparency = 0.0); + +protected: + vcl::Region m_aClipRegion; + SvpCairoTextRender m_aTextRenderImpl; + +protected: + virtual bool blendBitmap( const SalTwoRect&, const SalBitmap& rBitmap ) override; + virtual bool blendAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + virtual bool drawAlphaBitmap( const SalTwoRect&, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap ) override; + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) override; + + cairo_t* createTmpCompatibleCairoContext() const; + +public: + SvpSalGraphics(); + virtual ~SvpSalGraphics() override; + + virtual SalGraphicsImpl* GetImpl() const override { return nullptr; }; + virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override; + virtual sal_uInt16 GetBitCount() const override; + virtual long GetGraphicsWidth() const override; + + virtual void ResetClipRegion() override; + virtual bool setClipRegion( const vcl::Region& ) override; + + virtual void SetLineColor() override; + virtual void SetLineColor( Color nColor ) override; + virtual void SetFillColor() override; + virtual void SetFillColor( Color nColor ) override; + + virtual void SetXORMode( bool bSet, bool ) override; + + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + + virtual void SetTextColor( Color nColor ) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const override; + virtual void GetDevFontList( PhysicalFontCollection* ) override; + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) override; + virtual bool CreateFontSubset( const OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIds, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo + ) override; + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout( const GenericSalLayout& ) override; + virtual bool supportsOperation( OutDevSupportType ) const override; + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency ) override; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolyPolygon( sal_uInt32 nPoly, + const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry ) override; + virtual bool drawPolyLineBezier( sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + virtual bool drawPolygonBezier( sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) override; + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, SalGradient const & rGradient) override; + + virtual void copyArea( long nDestX, + long nDestY, + long nSrcX, + long nSrcY, + long nSrcWidth, + long nSrcHeight, + bool bWindowInvalidate) override; + virtual void copyBits( const SalTwoRect& rPosAry, + SalGraphics* pSrcGraphics ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap ) override; + void drawBitmap( const SalTwoRect& rPosAry, + const BitmapBuffer* pBuffer, + cairo_operator_t eOp ); + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) override; + virtual void drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + virtual Color getPixel( long nX, long nY ) override; + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) override; + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) override; + + virtual bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uInt32 nSize ) override; + + virtual SystemGraphicsData GetGraphicsData() const override; + + virtual OUString getRenderBackendName() const override { return "svp"; } + +#if ENABLE_CAIRO_CANVAS + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override; + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override; + virtual SystemFontData GetSysFontData( int nFallbacklevel ) const override; +#endif // ENABLE_CAIRO_CANVAS + + cairo_t* getCairoContext(bool bXorModeAllowed) const; + void releaseCairoContext(cairo_t* cr, bool bXorModeAllowed, const basegfx::B2DRange& rExtents) const; + static cairo_surface_t* createCairoSurface(const BitmapBuffer *pBuffer); + void clipRegion(cairo_t* cr); +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPGDI_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpinst.hxx b/vcl/inc/headless/svpinst.hxx new file mode 100644 index 000000000..ef20f0cab --- /dev/null +++ b/vcl/inc/headless/svpinst.hxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPINST_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPINST_HXX + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define VIRTUAL_DESKTOP_WIDTH 1024 +#define VIRTUAL_DESKTOP_HEIGHT 768 + +#ifdef IOS +#define SvpSalInstance AquaSalInstance +#endif + +class SvpSalInstance; +class SvpSalTimer final : public SalTimer +{ + SvpSalInstance* m_pInstance; +public: + SvpSalTimer( SvpSalInstance* pInstance ) : m_pInstance( pInstance ) {} + virtual ~SvpSalTimer() override; + + // override all pure virtual methods + virtual void Start( sal_uInt64 nMS ) override; + virtual void Stop() override; +}; + +class SvpSalFrame; +class GenPspGraphics; + +enum class SvpRequest +{ + NONE, + MainThreadDispatchOneEvent, + MainThreadDispatchAllEvents, +}; + +class SvpSalYieldMutex final : public SalYieldMutex +{ +private: + // note: these members might as well live in SvpSalInstance, but there is + // at least one subclass of SvpSalInstance (GTK3) that doesn't use them. + friend class SvpSalInstance; + // members for communication from main thread to non-main thread + int m_FeedbackFDs[2]; + osl::Condition m_NonMainWaitingYieldCond; + // members for communication from non-main thread to main thread + bool m_bNoYieldLock = false; // accessed only on main thread + std::mutex m_WakeUpMainMutex; // guard m_wakeUpMain & m_Request + std::condition_variable m_WakeUpMainCond; + bool m_wakeUpMain = false; + SvpRequest m_Request = SvpRequest::NONE; + + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; + +public: + SvpSalYieldMutex(); + virtual ~SvpSalYieldMutex() override; + + virtual bool IsCurrentThread() const override; +}; + +SalInstance* svp_create_SalInstance(); + +// NOTE: the functions IsMainThread, DoYield and Wakeup *require* the use of +// SvpSalYieldMutex; if a subclass uses something else it must override these +// (Wakeup is only called by SvpSalTimer and SvpSalFrame) +class VCL_DLLPUBLIC SvpSalInstance : public SalGenericInstance, public SalUserEventList +{ + timeval m_aTimeout; + sal_uLong m_nTimeoutMS; + oslThreadIdentifier m_MainThread; + + virtual void TriggerUserEventProcessing() override; + virtual void ProcessEvent( SalUserEvent aEvent ) override; + +public: + static SvpSalInstance* s_pDefaultInstance; + + SvpSalInstance( std::unique_ptr pMutex ); + virtual ~SvpSalInstance() override; + + void CloseWakeupPipe(bool log); + void CreateWakeupPipe(bool log); + void Wakeup(SvpRequest request = SvpRequest::NONE); + + void StartTimer( sal_uInt64 nMS ); + void StopTimer(); + + inline void registerFrame( SalFrame* pFrame ); + inline void deregisterFrame( SalFrame* pFrame ); + + bool CheckTimeout( bool bExecuteTimers = true ); + + // Frame + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + virtual void DestroyFrame( SalFrame* pFrame ) override; + + // Object (System Child Window) + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ) override; + virtual void DestroyObject( SalObject* pObject ) override; + + // 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 std::unique_ptr + CreateVirtualDevice( SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData *pData = nullptr ) override; + + // Printer + // pSetupData->mpDriverData can be 0 + // pSetupData must be updated with the current + // JobSetup + virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) override; + virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ) override; + virtual std::unique_ptr CreatePrinter( SalInfoPrinter* pInfoPrinter ) override; + + virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ) override; + virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) override; + virtual OUString GetDefaultPrinter() override; + virtual void PostPrintersChanged() override; + + // SalTimer + virtual SalTimer* CreateSalTimer() override; + // SalSystem + virtual SalSystem* CreateSalSystem() override; + // SalBitmap + virtual std::shared_ptr CreateSalBitmap() override; + + std::shared_ptr GetBackendCapabilities() override; + + // wait next event and dispatch + // must returned by UserEvent (SalFrame::PostEvent) + // and timer + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput( VclInputFlags nType ) override; + virtual bool IsMainThread() const override; + virtual void updateMainThread() override; + + virtual OpenGLContext* CreateOpenGLContext() override; + + virtual OUString GetConnectionIdentifier() override; + + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; + + virtual std::unique_ptr CreatePrintGraphics() override; +}; + +inline void SvpSalInstance::registerFrame( SalFrame* pFrame ) +{ + insertFrame( pFrame ); +} + +inline void SvpSalInstance::deregisterFrame( SalFrame* pFrame ) +{ + eraseFrame( pFrame ); +} + +VCL_DLLPUBLIC cairo_surface_t* get_underlying_cairo_surface(const VirtualDevice& rDevice); + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPINST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpprn.hxx b/vcl/inc/headless/svpprn.hxx new file mode 100644 index 000000000..3d241a96e --- /dev/null +++ b/vcl/inc/headless/svpprn.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPPRN_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPPRN_HXX + +#include + +class SvpSalInfoPrinter final : public PspSalInfoPrinter +{ +public: + virtual bool Setup( weld::Window* pFrame, ImplJobSetup* pSetupData ) override; +}; + +class SvpSalPrinter final : public PspSalPrinter +{ +public: + SvpSalPrinter( SalInfoPrinter* pInfoPrinter ); +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPPRN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/headless/svpvd.hxx b/vcl/inc/headless/svpvd.hxx new file mode 100644 index 000000000..7ec666709 --- /dev/null +++ b/vcl/inc/headless/svpvd.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HEADLESS_SVPVD_HXX +#define INCLUDED_VCL_INC_HEADLESS_SVPVD_HXX + +#include +#include +#include + +#include + +class SvpSalGraphics; +typedef struct _cairo_surface cairo_surface_t; + +class VCL_DLLPUBLIC SvpSalVirtualDevice : public SalVirtualDevice +{ + DeviceFormat m_eFormat; + cairo_surface_t* m_pRefSurface; + cairo_surface_t* m_pSurface; + bool m_bOwnsSurface; // nearly always true, except for edge case of tdf#127529 + basegfx::B2IVector m_aFrameSize; + std::vector< SvpSalGraphics* > m_aGraphics; + + void CreateSurface(long nNewDX, long nNewDY, sal_uInt8 *const pBuffer); + +protected: + SvpSalGraphics* AddGraphics(SvpSalGraphics* aGraphics); + +public: + SvpSalVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface, cairo_surface_t* pPreExistingTarget); + virtual ~SvpSalVirtualDevice() override; + + // SalVirtualDevice + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + virtual bool SetSize( long nNewDX, long nNewDY ) override; + virtual bool SetSizeUsingBuffer( long nNewDX, long nNewDY, + sal_uInt8 * pBuffer + ) override; + + cairo_surface_t* GetSurface() const { return m_pSurface; } + + // SalGeometryProvider + virtual long GetWidth() const override; + virtual long GetHeight() const override; +}; + +#endif // INCLUDED_VCL_INC_HEADLESS_SVPVD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/helpwin.hxx b/vcl/inc/helpwin.hxx new file mode 100644 index 000000000..089f7417c --- /dev/null +++ b/vcl/inc/helpwin.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_HELPWIN_HXX +#define INCLUDED_VCL_INC_HELPWIN_HXX + +#include +#include + +enum class QuickHelpFlags; +struct ImplSVHelpData; + +/// A tooltip: adds tips to widgets in a floating / popup window. +class HelpTextWindow final : public FloatingWindow +{ +private: + tools::Rectangle maHelpArea; // If next Help for the same rectangle w/ same text, then keep window + + tools::Rectangle maTextRect; // For wrapped text in QuickHelp + + OUString maHelpText; + + Timer maShowTimer; + Timer maHideTimer; + + sal_uInt16 mnHelpWinStyle; + QuickHelpFlags mnStyle; + +private: + DECL_LINK( TimerHdl, Timer*, void ); + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + virtual void ApplySettings(vcl::RenderContext& rRenderContext) override; + + virtual OUString GetText() const override; + void ImplShow(); + + virtual void dispose() override; +public: + HelpTextWindow( vcl::Window* pParent, const OUString& rText, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle ); + virtual ~HelpTextWindow() override; + + const OUString& GetHelpText() const { return maHelpText; } + void SetHelpText( const OUString& rHelpText ); + sal_uInt16 GetWinStyle() const { return mnHelpWinStyle; } + QuickHelpFlags GetStyle() const { return mnStyle; } + + // only remember: + void SetHelpArea( const tools::Rectangle& rRect ) { maHelpArea = rRect; } + + void ShowHelp(bool bNoDelay); + + Size CalcOutSize() const; + const tools::Rectangle& GetHelpArea() const { return maHelpArea; } +}; + +void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle, + const OUString& rHelpText, + const Point& rScreenPos, const tools::Rectangle& rHelpArea ); +VCL_DLLPUBLIC void ImplDestroyHelpWindow( bool bUpdateHideTime ); +void ImplDestroyHelpWindow(ImplSVHelpData& rHelpData, bool bUpdateHideTime); +void ImplSetHelpWindowPos( vcl::Window* pHelpWindow, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle, + const Point& rPos, const tools::Rectangle& rHelpArea ); + +#endif // INCLUDED_VCL_INC_HELPWIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/hyperlabel.hxx b/vcl/inc/hyperlabel.hxx new file mode 100644 index 000000000..c43dbb469 --- /dev/null +++ b/vcl/inc/hyperlabel.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_HYPERLABEL_HXX +#define INCLUDED_VCL_HYPERLABEL_HXX + +#include + +#include + +namespace vcl +{ + class HyperLabelImpl; + + class HyperLabel final : public FixedText + { + std::unique_ptr m_pImpl; + Link maClickHdl; + + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + + void implInit(); + + using FixedText::CalcMinimumSize; + + public: + HyperLabel( vcl::Window* _pParent, WinBits _nWinStyle ); + virtual ~HyperLabel( ) override; + virtual void dispose() override; + + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + virtual void ApplySettings(vcl::RenderContext& rRenderContext) override; + + void SetID( sal_Int16 ID ); + sal_Int16 GetID() const; + + void SetIndex( sal_Int32 Index ); + sal_Int32 GetIndex() const; + + void SetLabel( const OUString& _rText ); + + void ToggleBackgroundColor( const Color& _rGBColor ); + void SetInteractive( bool _bInteractive ); + + void SetClickHdl( const Link& rLink ) { maClickHdl = rLink; } + + Size const & CalcMinimumSize( long nMaxWidth ) const; + }; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx new file mode 100644 index 000000000..09d1a0b02 --- /dev/null +++ b/vcl/inc/iconview.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVTOOLS_ICONVIEW_HXX +#define INCLUDED_SVTOOLS_ICONVIEW_HXX + +#include + +class IconView final : public SvTreeListBox +{ +public: + IconView( vcl::Window* pParent, WinBits nBits ); + + virtual void Resize() override; + + virtual tools::Rectangle GetFocusRect(const SvTreeListEntry*, long nEntryPos) override; + + void PaintEntry( SvTreeListEntry&, long nX, long nY, vcl::RenderContext& rRenderContext); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/image.h b/vcl/inc/image.h new file mode 100644 index 000000000..c25015624 --- /dev/null +++ b/vcl/inc/image.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMAGE_H +#define INCLUDED_VCL_INC_IMAGE_H + +#include + +class ImplImage +{ +private: + BitmapChecksum maBitmapChecksum; + /// if non-empty: cached original size of maStockName else Size of maBitmap + Size maSizePixel; + Size maPreferedSizePixel; + /// If set - defines the bitmap via images.zip* + OUString maStockName; + + + /// Original bitmap - or cache of a potentially scaled bitmap + BitmapEx maBitmapEx; + BitmapEx maDisabledBitmapEx; + + bool loadStockAtScale(double fScale, BitmapEx &rBitmapEx); + +public: + ImplImage(const BitmapEx& rBitmapEx); + ImplImage(const OUString &aStockName, Size const & rPreferedSize); + + bool isStock() const + { + return maStockName.getLength() > 0; + } + + OUString getStock() const + { + return maStockName; + } + + /// get size in co-ordinates not scaled for HiDPI + Size getSizePixel(); + /// Legacy - the original bitmap + BitmapEx const & getBitmapEx(bool bDisabled = false); + /// Taking account of HiDPI scaling + BitmapEx const & getBitmapExForHiDPI(bool bDisabled = false); + + bool isEqual(const ImplImage &ref) const; + bool isSizeEmpty() const + { + return maSizePixel == Size(); + } +}; + +#endif // INCLUDED_VCL_INC_IMAGE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/imagerepository.hxx b/vcl/inc/imagerepository.hxx new file mode 100644 index 000000000..a1a28d3fa --- /dev/null +++ b/vcl/inc/imagerepository.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IMAGEREPOSITORY_HXX +#define INCLUDED_VCL_IMAGEREPOSITORY_HXX + +#include +#include + +class BitmapEx; + + +namespace vcl +{ + + + //= ImageRepository + + // provides access to the application's image repository (image.zip) + class 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. + @return + whether or not the image could be loaded successfully. + */ + static bool loadImage( + const OUString& _rName, + BitmapEx& _out_rImage + ); + }; + + +} // namespace vcl + + +#endif // INCLUDED_VCL_IMAGEREPOSITORY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impanmvw.hxx b/vcl/inc/impanmvw.hxx new file mode 100644 index 000000000..b4e634071 --- /dev/null +++ b/vcl/inc/impanmvw.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SOURCE_GDI_IMPANMVW_HXX +#define INCLUDED_VCL_SOURCE_GDI_IMPANMVW_HXX + +#include +#include + +class Animation; +class OutputDevice; +class VirtualDevice; +struct AnimationBitmap; + +struct AInfo +{ + Point aStartOrg; + Size aStartSize; + VclPtr pOutDev; + void* pViewData; + long nExtraData; + bool bPause; + + AInfo(); +}; + + +class ImplAnimView +{ +private: + + friend class Animation; + + Animation* mpParent; + VclPtr mpRenderContext; + long mnExtraData; + Point maPt; + Point maDispPt; + Point maRestPt; + Size maSz; + Size maSzPix; + Size maDispSz; + Size maRestSz; + vcl::Region maClip; + VclPtr mpBackground; + VclPtr mpRestore; + sal_uLong mnActPos; + Disposal meLastDisposal; + bool mbIsPaused; + bool mbIsMarked; + bool mbIsMirroredHorizontally; + bool mbIsMirroredVertically; + +public: + ~ImplAnimView(); +private: + ImplAnimView( Animation* pParent, OutputDevice* pOut, + const Point& rPt, const Size& rSz, sal_uLong nExtraData, + OutputDevice* pFirstFrameOutDev = nullptr ); + + bool matches(const OutputDevice* pOut, long nExtraData) const; + void drawToPos( sal_uLong nPos ); + void draw( sal_uLong nPos, VirtualDevice* pVDev=nullptr ); + void repaint(); + AInfo* createAInfo() const; + + void getPosSize( const AnimationBitmap& rAnm, Point& rPosPix, Size& rSizePix ); + + const Point& getOutPos() const { return maPt; } + + const Size& getOutSizePix() const { return maSzPix; } + + void pause( bool bIsPaused ) { mbIsPaused = bIsPaused; } + bool isPause() const { return mbIsPaused; } + + void setMarked( bool bIsMarked ) { mbIsMarked = bIsMarked; } + bool isMarked() const { return mbIsMarked; } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impdel.hxx b/vcl/inc/impdel.hxx new file mode 100644 index 000000000..308872b9c --- /dev/null +++ b/vcl/inc/impdel.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IMPDEL_HXX +#define INCLUDED_VCL_IMPDEL_HXX + +#include + +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 = nullptr; } + bool isDeleted() const { return (m_pNotifier == nullptr); } +}; + +inline void DeletionNotifier::notifyDelete() +{ + for( auto& rListener : m_aListeners ) + rListener->deleted(); + + m_aListeners.clear(); +} + +} // namespace vcl + +#endif // INCLUDED_VCL_IMPDEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impfont.hxx b/vcl/inc/impfont.hxx new file mode 100644 index 000000000..7f4301d97 --- /dev/null +++ b/vcl/inc/impfont.hxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPFONT_HXX +#define INCLUDED_VCL_INC_IMPFONT_HXX + +#include +#include +#include +#include +#include +#include + +#include "fontselect.hxx" + +/* The following class is extraordinarily similar to FontAttributes. */ + +class ImplFont +{ +public: + explicit ImplFont(); + explicit ImplFont( const ImplFont& ); + + // device independent font functions + const OUString& GetFamilyName() const { return maFamilyName; } + FontFamily GetFamilyType() { if(meFamily==FAMILY_DONTKNOW) AskConfig(); return meFamily; } + const OUString& GetStyleName() const { return maStyleName; } + + FontWeight GetWeight() { if(meWeight==WEIGHT_DONTKNOW) AskConfig(); return meWeight; } + FontItalic GetItalic() { if(meItalic==ITALIC_DONTKNOW) AskConfig(); return meItalic; } + FontPitch GetPitch() { if(mePitch==PITCH_DONTKNOW) AskConfig(); return mePitch; } + FontWidth GetWidthType() { if(meWidthType==WIDTH_DONTKNOW) AskConfig(); return meWidthType; } + TextAlign GetAlignment() const { return meAlign; } + rtl_TextEncoding GetCharSet() const { return meCharSet; } + const Size& GetFontSize() const { return maAverageFontSize; } + + bool IsSymbolFont() const { return mbSymbolFlag; } + + void SetFamilyName( const OUString& sFamilyName ) { maFamilyName = sFamilyName; } + void SetStyleName( const OUString& sStyleName ) { maStyleName = sStyleName; } + void SetFamilyType( const FontFamily eFontFamily ) { meFamily = eFontFamily; } + + void SetPitch( const FontPitch ePitch ) { mePitch = ePitch; } + void SetItalic( const FontItalic eItalic ) { meItalic = eItalic; } + void SetWeight( const FontWeight eWeight ) { meWeight = eWeight; } + void SetWidthType( const FontWidth eWidthType ) { meWidthType = eWidthType; } + void SetAlignment( const TextAlign eAlignment ) { meAlign = eAlignment; } + void SetCharSet( const rtl_TextEncoding eCharSet ) { meCharSet = eCharSet; } + void SetFontSize( const Size& rSize ) { maAverageFontSize = rSize; } + + void SetSymbolFlag( const bool bSymbolFlag ) { mbSymbolFlag = bSymbolFlag; } + + // straight properties, no getting them from AskConfig() + FontFamily GetFamilyTypeNoAsk() const { return meFamily; } + FontWeight GetWeightNoAsk() const { return meWeight; } + FontItalic GetItalicNoAsk() const { return meItalic; } + FontPitch GetPitchNoAsk() const { return mePitch; } + FontWidth GetWidthTypeNoAsk() const { return meWidthType; } + + // device dependent functions + int GetQuality() const { return mnQuality; } + + void SetQuality( int nQuality ) { mnQuality = nQuality; } + void IncreaseQualityBy( int nQualityAmount ) { mnQuality += nQualityAmount; } + void DecreaseQualityBy( int nQualityAmount ) { mnQuality -= nQualityAmount; } + + bool operator==( const ImplFont& ) const; + +private: + friend class vcl::Font; + friend SvStream& ReadImplFont( SvStream& rIStm, ImplFont& ); + friend SvStream& WriteImplFont( SvStream& rOStm, const ImplFont& ); + + void AskConfig(); + + // Device independent variables + OUString maFamilyName; + OUString maStyleName; + FontWeight meWeight; + FontFamily meFamily; + FontPitch mePitch; + FontWidth meWidthType; + FontItalic meItalic; + TextAlign meAlign; + FontLineStyle meUnderline; + FontLineStyle meOverline; + FontStrikeout meStrikeout; + FontRelief meRelief; + FontEmphasisMark meEmphasisMark; + FontKerning meKerning; + Size maAverageFontSize; + rtl_TextEncoding meCharSet; + + LanguageTag maLanguageTag; + LanguageTag maCJKLanguageTag; + + // Flags - device independent + bool mbSymbolFlag:1, + mbOutline:1, + mbConfigLookup:1, // config lookup should only be done once + mbShadow:1, + mbVertical:1, + mbTransparent:1; // compatibility, now on output device + + // deprecated variables - device independent + Color maColor; // compatibility, now on output device + Color maFillColor; // compatibility, now on output device + + // Device dependent variables + bool mbWordLine:1; + + // TODO: metric data, should be migrated to ImplFontMetric + short mnOrientation; + + int mnQuality; + +}; + +#endif // INCLUDED_VCL_INC_IMPFONT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impfontcache.hxx b/vcl/inc/impfontcache.hxx new file mode 100644 index 000000000..78dfb4a71 --- /dev/null +++ b/vcl/inc/impfontcache.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPFONTCACHE_HXX +#define INCLUDED_VCL_INC_IMPFONTCACHE_HXX + +#include + +#include +#include +#include +#include + +#include "fontselect.hxx" + +class Size; +namespace vcl { class Font; } +class PhysicalFontCollection; + +// TODO: closely couple with PhysicalFontCollection + +struct GlyphBoundRectCacheKey +{ + const LogicalFontInstance* m_pFont; + const sal_GlyphId m_nId; + + GlyphBoundRectCacheKey(const LogicalFontInstance* pFont, sal_GlyphId nID) + : m_pFont(pFont), m_nId(nID) + {} + + bool operator==(GlyphBoundRectCacheKey const& aOther) const + { return m_pFont == aOther.m_pFont && m_nId == aOther.m_nId; } +}; + +struct GlyphBoundRectCacheHash +{ + std::size_t operator()(GlyphBoundRectCacheKey const& aCache) const + { + std::size_t seed = 0; + boost::hash_combine(seed, aCache.m_pFont); + boost::hash_combine(seed, aCache.m_nId); + return seed; + } +}; + +typedef o3tl::lru_map GlyphBoundRectCache; +typedef GlyphBoundRectCache::key_value_pair_t GlyphBoundRectCachePair; + +class ImplFontCache +{ +private: + // cache of recently used font instances + struct IFSD_Equal { bool operator()( const FontSelectPattern&, const FontSelectPattern& ) const; }; + struct IFSD_Hash { size_t operator()( const FontSelectPattern& ) const; }; + typedef o3tl::lru_map, IFSD_Hash, IFSD_Equal> FontInstanceList; + typedef FontInstanceList::key_value_pair_t FontInstanceListPair; + + LogicalFontInstance* mpLastHitCacheEntry; ///< keeps the last hit cache entry + FontInstanceList maFontInstanceList; + GlyphBoundRectCache m_aBoundRectCache; + + rtl::Reference GetFontInstance(PhysicalFontCollection const*, FontSelectPattern&); + +public: + ImplFontCache(); + ~ImplFontCache(); + + rtl::Reference GetFontInstance(PhysicalFontCollection const *, + const vcl::Font&, const Size& rPixelSize, float fExactHeight, bool bNonAntialias = false); + rtl::Reference GetGlyphFallbackFont( PhysicalFontCollection const *, FontSelectPattern&, + LogicalFontInstance* pLogicalFont, + int nFallbackLevel, OUString& rMissingCodes ); + + bool GetCachedGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); + void CacheGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); + + void Invalidate(); +}; + +#endif // INCLUDED_VCL_INC_IMPFONTCACHE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impfontcharmap.hxx b/vcl/inc/impfontcharmap.hxx new file mode 100644 index 000000000..eaa99dbe2 --- /dev/null +++ b/vcl/inc/impfontcharmap.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPFONTCHARMAP_HXX +#define INCLUDED_VCL_INC_IMPFONTCHARMAP_HXX + +#include +#include + +class ImplFontCharMap; +typedef tools::SvRef ImplFontCharMapRef; + +class CmapResult; + +class ImplFontCharMap : public SvRefBase +{ +public: + explicit ImplFontCharMap( const CmapResult& ); + virtual ~ImplFontCharMap() override; + +private: + friend class FontCharMap; + + ImplFontCharMap( const ImplFontCharMap& ) = delete; + void operator=( const ImplFontCharMap& ) = delete; + + static ImplFontCharMapRef const & getDefaultMap( bool bSymbols=false); + bool isDefaultMap() const; + +private: + const sal_uInt32* mpRangeCodes; // pairs of StartCode/(EndCode+1) + const int* mpStartGlyphs; // range-specific mapper to glyphs + const sal_uInt16* mpGlyphIds; // individual glyphid mappings + int mnRangeCount; + int mnCharCount; // covered codepoints +}; + +bool VCL_DLLPUBLIC ParseCMAP( const unsigned char* pRawData, int nRawLength, CmapResult& ); + +#endif // INCLUDED_VCL_INC_IMPFONTCHARMAP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impfontmetricdata.hxx b/vcl/inc/impfontmetricdata.hxx new file mode 100644 index 000000000..d801b9e41 --- /dev/null +++ b/vcl/inc/impfontmetricdata.hxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPFONTMETRICDATA_HXX +#define INCLUDED_VCL_INC_IMPFONTMETRICDATA_HXX + +#include +#include +#include "fontattributes.hxx" +#include "sft.hxx" + +#include + +class ImplFontMetricData; +typedef tools::SvRef ImplFontMetricDataRef; + +class OutputDevice; +class FontSelectPattern; +class LogicalFontInstance; + +class VCL_DLLPUBLIC ImplFontMetricData : public FontAttributes, public SvRefBase +{ +public: + explicit ImplFontMetricData( const FontSelectPattern& ); + + // font instance attributes from the font request + long GetWidth() const { return mnWidth; } + short GetOrientation() const { return mnOrientation; } + + void SetWidth(long nWidth) { mnWidth=nWidth; } + void SetOrientation(short nOrientation) { mnOrientation=nOrientation; } + + // font metrics measured for the font instance + long GetAscent() const { return mnAscent; } + long GetDescent() const { return mnDescent; } + long GetInternalLeading() const { return mnIntLeading; } + long GetExternalLeading() const { return mnExtLeading; } + int GetSlant() const { return mnSlant; } + long GetMinKashida() const { return mnMinKashida; } + + void SetSlant(int nSlant) { mnSlant=nSlant; } + void SetMinKashida( long nMinKashida ) { mnMinKashida=nMinKashida; } + + // font attributes queried from the font instance + bool IsFullstopCentered() const { return mbFullstopCentered; } + long GetBulletOffset() const { return mnBulletOffset; } + + void SetFullstopCenteredFlag(bool bFullstopCentered) { mbFullstopCentered = bFullstopCentered; } + + // font metrics that are usually derived from the measurements + long GetUnderlineSize() const { return mnUnderlineSize; } + long GetUnderlineOffset() const { return mnUnderlineOffset; } + long GetBoldUnderlineSize() const { return mnBUnderlineSize; } + long GetBoldUnderlineOffset() const { return mnBUnderlineOffset; } + long GetDoubleUnderlineSize() const { return mnDUnderlineSize; } + long GetDoubleUnderlineOffset1() const { return mnDUnderlineOffset1; } + long GetDoubleUnderlineOffset2() const { return mnDUnderlineOffset2; } + long GetWavelineUnderlineSize() const { return mnWUnderlineSize; } + long GetWavelineUnderlineOffset() const { return mnWUnderlineOffset; } + long GetAboveUnderlineSize() const { return mnAboveUnderlineSize; } + long GetAboveUnderlineOffset() const { return mnAboveUnderlineOffset; } + long GetAboveBoldUnderlineSize() const { return mnAboveBUnderlineSize; } + long GetAboveBoldUnderlineOffset() const { return mnAboveBUnderlineOffset; } + long GetAboveDoubleUnderlineSize() const { return mnAboveDUnderlineSize; } + long GetAboveDoubleUnderlineOffset1() const { return mnAboveDUnderlineOffset1; } + long GetAboveDoubleUnderlineOffset2() const { return mnAboveDUnderlineOffset2; } + long GetAboveWavelineUnderlineSize() const { return mnAboveWUnderlineSize; } + long GetAboveWavelineUnderlineOffset() const { return mnAboveWUnderlineOffset; } + long GetStrikeoutSize() const { return mnStrikeoutSize; } + long GetStrikeoutOffset() const { return mnStrikeoutOffset; } + long GetBoldStrikeoutSize() const { return mnBStrikeoutSize; } + long GetBoldStrikeoutOffset() const { return mnBStrikeoutOffset; } + long GetDoubleStrikeoutSize() const { return mnDStrikeoutSize; } + long GetDoubleStrikeoutOffset1() const { return mnDStrikeoutOffset1; } + long GetDoubleStrikeoutOffset2() const { return mnDStrikeoutOffset2; } + + void ImplInitTextLineSize( const OutputDevice* pDev ); + void ImplInitAboveTextLineSize(); + void ImplInitFlags( const OutputDevice* pDev ); + void ImplCalcLineSpacing(LogicalFontInstance *pFontInstance); + +private: + bool ShouldUseWinMetrics(const vcl::TTGlobalFontInfo& rInfo); + + // font instance attributes from the font request + long mnHeight; // Font size + 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 + bool mbFullstopCentered; + long mnBulletOffset; // Offset to position non-print character + + // font metrics that are usually derived from the measurements + long mnUnderlineSize; // Lineheight of Underline + long mnUnderlineOffset; // Offset from Underline to Baseline + long mnBUnderlineSize; // Height of bold underline + long mnBUnderlineOffset; // Offset from bold underline to baseline + long mnDUnderlineSize; // Height of double underline + long mnDUnderlineOffset1; // Offset from double underline to baseline + long mnDUnderlineOffset2; // Offset from double underline to baseline + long mnWUnderlineSize; // Height of WaveLine underline + long mnWUnderlineOffset; // Offset from WaveLine underline to baseline, but centrered to WaveLine + long mnAboveUnderlineSize; // Height of single underline (for Vertical Right) + long mnAboveUnderlineOffset; // Offset from single underline to baseline (for Vertical Right) + long mnAboveBUnderlineSize; // Height of bold underline (for Vertical Right) + long mnAboveBUnderlineOffset; // Offset from bold underline to baseline (for Vertical Right) + long mnAboveDUnderlineSize; // Height of double underline (for Vertical Right) + long mnAboveDUnderlineOffset1; // Offset from double underline to baseline (for Vertical Right) + long mnAboveDUnderlineOffset2; // Offset from double underline to baseline (for Vertical Right) + long mnAboveWUnderlineSize; // Height of WaveLine-strike-out (for Vertical Right) + long mnAboveWUnderlineOffset; // Offset from WaveLine-strike-out to baseline, but centrered to the WaveLine (for Vertical Right) + long mnStrikeoutSize; // Height of single strike-out + long mnStrikeoutOffset; // Offset from single strike-out to baseline + long mnBStrikeoutSize; // Height of bold strike-out + long mnBStrikeoutOffset; // Offset of bold strike-out to baseline + long mnDStrikeoutSize; // Height of double strike-out + long mnDStrikeoutOffset1; // Offset of double strike-out to baseline + long mnDStrikeoutOffset2; // Offset of double strike-out to baseline + +}; + +#endif // INCLUDED_VCL_INC_IMPFONTMETRICDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx new file mode 100644 index 000000000..da56b660d --- /dev/null +++ b/vcl/inc/impglyphitem.hxx @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IMPGLYPHITEM_HXX +#define INCLUDED_VCL_IMPGLYPHITEM_HXX + +#include +#include +#include +#include +#include +#include + +#include "fontinstance.hxx" + +enum class GlyphItemFlags +{ + NONE = 0, + IS_IN_CLUSTER = 0x001, + IS_RTL_GLYPH = 0x002, + IS_DIACRITIC = 0x004, + IS_VERTICAL = 0x008, + IS_SPACING = 0x010, + ALLOW_KASHIDA = 0x020, + IS_DROPPED = 0x040, + IS_CLUSTER_START = 0x080 +}; +namespace o3tl +{ +template <> struct typed_flags : is_typed_flags +{ +}; +}; + +class VCL_DLLPUBLIC GlyphItem +{ + sal_GlyphId m_aGlyphId; + int m_nCharCount; // number of characters making up this glyph + int m_nOrigWidth; // original glyph width + LogicalFontInstance* m_pFontInstance; + int m_nCharPos; // index in string + GlyphItemFlags m_nFlags; + int m_nXOffset; + +public: + int m_nNewWidth; // width after adjustments + Point m_aLinearPos; // absolute position of non rotated string + + GlyphItem(int nCharPos, int nCharCount, sal_GlyphId aGlyphId, const Point& rLinearPos, + GlyphItemFlags nFlags, int nOrigWidth, int nXOffset, + LogicalFontInstance* pFontInstance) + : m_aGlyphId(aGlyphId) + , m_nCharCount(nCharCount) + , m_nOrigWidth(nOrigWidth) + , m_pFontInstance(pFontInstance) + , m_nCharPos(nCharPos) + , m_nFlags(nFlags) + , m_nXOffset(nXOffset) + , m_nNewWidth(nOrigWidth) + , m_aLinearPos(rLinearPos) + { + assert(m_pFontInstance); + } + + bool IsInCluster() const { return bool(m_nFlags & GlyphItemFlags::IS_IN_CLUSTER); } + bool IsRTLGlyph() const { return bool(m_nFlags & GlyphItemFlags::IS_RTL_GLYPH); } + bool IsDiacritic() const { return bool(m_nFlags & GlyphItemFlags::IS_DIACRITIC); } + bool IsVertical() const { return bool(m_nFlags & GlyphItemFlags::IS_VERTICAL); } + bool IsSpacing() const { return bool(m_nFlags & GlyphItemFlags::IS_SPACING); } + bool AllowKashida() const { return bool(m_nFlags & GlyphItemFlags::ALLOW_KASHIDA); } + bool IsDropped() const { return bool(m_nFlags & GlyphItemFlags::IS_DROPPED); } + bool IsClusterStart() const { return bool(m_nFlags & GlyphItemFlags::IS_CLUSTER_START); } + + inline bool GetGlyphBoundRect(tools::Rectangle&) const; + inline bool GetGlyphOutline(basegfx::B2DPolyPolygon&) const; + inline void dropGlyph(); + + sal_GlyphId glyphId() const { return m_aGlyphId; } + int charCount() const { return m_nCharCount; } + int origWidth() const { return m_nOrigWidth; } + int charPos() const { return m_nCharPos; } + int xOffset() const { return m_nXOffset; } +}; + +VCL_DLLPUBLIC bool GlyphItem::GetGlyphBoundRect(tools::Rectangle& rRect) const +{ + return m_pFontInstance->GetGlyphBoundRect(m_aGlyphId, rRect, IsVertical()); +} + +VCL_DLLPUBLIC bool GlyphItem::GetGlyphOutline(basegfx::B2DPolyPolygon& rPoly) const +{ + return m_pFontInstance->GetGlyphOutline(m_aGlyphId, rPoly, IsVertical()); +} + +void GlyphItem::dropGlyph() +{ + m_nCharPos = -1; + m_nFlags |= GlyphItemFlags::IS_DROPPED; +} + +class SalLayoutGlyphsImpl : public std::vector +{ + friend class GenericSalLayout; + +public: + SalLayoutGlyphsImpl* clone(SalLayoutGlyphs& rGlyphs) const; + LogicalFontInstance& GetFont() const { return *m_rFontInstance; } + bool IsValid() const; + void Invalidate(); + +private: + mutable rtl::Reference m_rFontInstance; + SalLayoutFlags mnFlags = SalLayoutFlags::NONE; + + SalLayoutGlyphsImpl(SalLayoutGlyphs& rGlyphs, LogicalFontInstance& rFontInstance) + : m_rFontInstance(&rFontInstance) + { + rGlyphs.m_pImpl = this; + } +}; + +#endif // INCLUDED_VCL_IMPGLYPHITEM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/impgraph.hxx b/vcl/inc/impgraph.hxx new file mode 100644 index 000000000..749a5b82a --- /dev/null +++ b/vcl/inc/impgraph.hxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPGRAPH_HXX +#define INCLUDED_VCL_INC_IMPGRAPH_HXX + +#include +#include +#include +#include +#include "graphic/Manager.hxx" +#include "graphic/GraphicID.hxx" + +struct ImpSwapInfo +{ + MapMode maPrefMapMode; + Size maPrefSize; + Size maSizePixel; + + bool mbIsAnimated; + bool mbIsEPS; + bool mbIsTransparent; + bool mbIsAlpha; + + sal_uInt32 mnAnimationLoopCount; +}; + +class OutputDevice; +class GfxLink; +class ImpSwapFile; +class GraphicConversionParameters; +class ImpGraphic; + +class VCL_DLLPUBLIC ImpGraphic final +{ + friend class Graphic; + friend class GraphicID; + friend class vcl::graphic::Manager; + +private: + + GDIMetaFile maMetaFile; + BitmapEx maBitmapEx; + /// If maBitmapEx is empty, this preferred size will be set on it when it gets initialized. + Size maExPrefSize; + ImpSwapInfo maSwapInfo; + std::unique_ptr mpAnimation; + std::shared_ptr mpContext; + std::shared_ptr mpSwapFile; + std::shared_ptr mpGfxLink; + GraphicType meType; + mutable sal_uLong mnSizeBytes; + bool mbSwapOut; + bool mbDummyContext; + std::shared_ptr maVectorGraphicData; + // cache checksum computation + mutable BitmapChecksum mnChecksum = 0; + + std::unique_ptr mpGraphicID; + GraphicExternalLink maGraphicExternalLink; + + std::chrono::high_resolution_clock::time_point maLastUsed; + bool mbPrepared; + +public: + ImpGraphic(); + ImpGraphic( const ImpGraphic& rImpGraphic ); + ImpGraphic( ImpGraphic&& rImpGraphic ) noexcept; + ImpGraphic( const GraphicExternalLink& rExternalLink); + ImpGraphic( const Bitmap& rBmp ); + ImpGraphic( const BitmapEx& rBmpEx ); + ImpGraphic(const std::shared_ptr& rVectorGraphicDataPtr); + ImpGraphic( const Animation& rAnimation ); + ImpGraphic( const GDIMetaFile& rMtf ); + ~ImpGraphic(); + + void ImplSetPrepared(bool bAnimated, const Size* pSizeHint); + +private: + + ImpGraphic& operator=( const ImpGraphic& rImpGraphic ); + ImpGraphic& operator=( ImpGraphic&& rImpGraphic ); + bool operator==( const ImpGraphic& rImpGraphic ) const; + bool operator!=( const ImpGraphic& rImpGraphic ) const { return !( *this == rImpGraphic ); } + + OUString const & getOriginURL() const + { + return maGraphicExternalLink.msURL; + } + + void setOriginURL(OUString const & rOriginURL) + { + maGraphicExternalLink.msURL = rOriginURL; + } + + OString getUniqueID() + { + if (!mpGraphicID) + mpGraphicID.reset(new GraphicID(*this)); + return mpGraphicID->getIDString(); + } + + void createSwapInfo(); + void ImplClearGraphics(); + void ImplClear(); + + GraphicType ImplGetType() const { return meType;} + void ImplSetDefaultType(); + bool ImplIsSupportedGraphic() const; + + bool ImplIsTransparent() const; + bool ImplIsAlpha() const; + bool ImplIsAnimated() const; + bool ImplIsEPS() const; + + bool isAvailable() const; + bool makeAvailable(); + + Bitmap ImplGetBitmap(const GraphicConversionParameters& rParameters) const; + BitmapEx ImplGetBitmapEx(const GraphicConversionParameters& rParameters) const; + /// Gives direct access to the contained BitmapEx. + const BitmapEx& ImplGetBitmapExRef() const; + Animation ImplGetAnimation() const; + const GDIMetaFile& ImplGetGDIMetaFile() const; + + Size ImplGetSizePixel() const; + + Size ImplGetPrefSize() const; + void ImplSetPrefSize( const Size& rPrefSize ); + + MapMode ImplGetPrefMapMode() const; + void ImplSetPrefMapMode( const MapMode& rPrefMapMode ); + + sal_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, + const Size& rDestSize, + long nExtraData, + OutputDevice* pFirstFrameOutDev ); + void ImplStopAnimation( OutputDevice* pOutputDevice, + long nExtraData ); + + void ImplSetAnimationNotifyHdl( const Link& rLink ); + Link ImplGetAnimationNotifyHdl() const; + + sal_uInt32 ImplGetAnimationLoopCount() const; + +private: + + std::shared_ptr& ImplGetContext() { return mpContext;} + void ImplSetContext( const std::shared_ptr& pReader ); + void ImplSetDummyContext( bool value ) { mbDummyContext = value; } + bool ImplReadEmbedded( SvStream& rIStream ); + bool ImplWriteEmbedded( SvStream& rOStream ); + + bool swapInFromStream(SvStream* pIStm); + + bool ImplIsDummyContext() const { return mbDummyContext; } + void ImplSetLink( const std::shared_ptr& ); + std::shared_ptr ImplGetSharedGfxLink() const; + GfxLink ImplGetLink(); + bool ImplIsLink() const; + + BitmapChecksum ImplGetChecksum() const; + + bool ImplExportNative( SvStream& rOStm ) const; + + friend void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic); + friend void ReadImpGraphic(SvStream& rIStm, ImpGraphic& rImpGraphic); + + const std::shared_ptr& getVectorGraphicData() const; + + /// Gets the bitmap replacement for a vector graphic. + BitmapEx getVectorGraphicReplacement() const; + + bool ensureAvailable () const; + + bool loadPrepared(); + + sal_Int32 getPageNumber() const; + +public: + bool swapIn(); + bool swapOut(); + bool isSwappedOut() const { return mbSwapOut; } + OUString getSwapFileURL(); +}; + +#endif // INCLUDED_VCL_INC_IMPGRAPH_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/implimagetree.hxx b/vcl/inc/implimagetree.hxx new file mode 100644 index 000000000..3656b66de --- /dev/null +++ b/vcl/inc/implimagetree.hxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IMPLIMAGETREE_HXX +#define INCLUDED_VCL_INC_IMPLIMAGETREE_HXX + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace com::sun::star::container { + class XNameAccess; +} + +struct ImageRequestParameters +{ + OUString msName; + OUString msStyle; + BitmapEx& mrBitmap; + bool mbLocalized; + ImageLoadFlags meFlags; + bool mbWriteImageToCache; + sal_Int32 mnScalePercentage; + + ImageRequestParameters(const OUString & rName, const OUString & rStyle, BitmapEx& rBitmap, bool bLocalized, + ImageLoadFlags eFlags, sal_Int32 nScalePercentage) + : msName(rName) + , msStyle(rStyle) + , mrBitmap(rBitmap) + , mbLocalized(bLocalized) + , meFlags(eFlags) + , mbWriteImageToCache(false) + , mnScalePercentage(nScalePercentage) + {} + + bool convertToDarkTheme(); + sal_Int32 scalePercentage(); +}; + +class ImplImageTree +{ +public: + ImplImageTree(); + ~ImplImageTree(); + + OUString getImageUrl( + OUString const & name, OUString const & style, OUString const & lang); + + std::shared_ptr getImageStream( + OUString const & rName, OUString const & rStyle, OUString const & rLang); + + bool loadImage( + OUString const & name, OUString const & style, + BitmapEx & bitmap, bool localized, + const ImageLoadFlags eFlags, + sal_Int32 nScalePercentage = -1); + + /** 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 maIconCache)*/ + void shutdown(); + + css::uno::Reference< css::container::XNameAccess > const & getNameAccess(); + +private: + ImplImageTree(const ImplImageTree&) = delete; + ImplImageTree& operator=(const ImplImageTree&) = delete; + + typedef std::unordered_map> IconCache; + typedef std::unordered_map> ScaledIconCache; + typedef std::unordered_map IconLinkHash; + + struct IconSet + { + OUString maURL; + css::uno::Reference maNameAccess; + ScaledIconCache maScaledIconCaches; + IconLinkHash maLinkHash; + + IconSet() + {} + + IconSet(const OUString & rURL) + : maURL(rURL) + {} + }; + + /// Remember all the (used) icon styles and individual icons in them. + /// Map between the theme name(s) and the content. + std::unordered_map maIconSets; + + /// Style used for the current operations; switches switch several times during fallback search. + OUString maCurrentStyle; + + IconSet& getCurrentIconSet() + { + return maIconSets[maCurrentStyle]; + } + + bool doLoadImage(ImageRequestParameters& rParameters); + + std::vector getPaths(OUString const & name, LanguageTag const & rLanguageTag); + + bool checkPathAccess(); + + void setStyle(OUString const & rStyle); + + void createStyle(); + + IconCache &getIconCache(const ImageRequestParameters& rParameters); + + bool iconCacheLookup(ImageRequestParameters& rParameters); + + bool findImage(std::vector const & rPaths, ImageRequestParameters& rParameters); + + void loadImageLinks(); + + void parseLinkFile(std::shared_ptr const & aStream); + + /// Return name of a real .png according to links.txt. + OUString const & getRealImageName(OUString const & rName); + + + /** Return name of the fallback style for the provided one. + + Must not be cyclic :-) The last theme in the chain returns an empty string. + */ + static OUString fallbackStyle(const OUString &rStyle); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/iosinst.hxx b/vcl/inc/ios/iosinst.hxx new file mode 100644 index 000000000..a937fb25f --- /dev/null +++ b/vcl/inc/ios/iosinst.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_IOS_IOSINST_HXX +#define INCLUDED_VCL_INC_IOS_IOSINST_HXX + +#include +#include +#include + +#include + +#include "headless/svpinst.hxx" +#include "headless/svpframe.hxx" + +class IosSalFrame; +class IosSalInstance : public SvpSalInstance +{ +public: + IosSalInstance( std::unique_ptr pMutex ); + virtual ~IosSalInstance(); + static IosSalInstance *getInstance(); + + SalSystem* CreateSalSystem() override; + + css::uno::Reference< css::uno::XInterface > CreateClipboard( const css::uno::Sequence< css::uno::Any >& i_rArguments ) override; + + void GetWorkArea( tools::Rectangle& rRect ); + SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; +}; + +#endif // INCLUDED_VCL_INC_IOS_IOSINST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/svsys.h b/vcl/inc/ios/svsys.h new file mode 100644 index 000000000..dcd14e79f --- /dev/null +++ b/vcl/inc/ios/svsys.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_IOS_SVSYS_H +#define INCLUDED_VCL_INC_IOS_SVSYS_H + +// ? + +#endif // INCLUDED_VCL_INC_IOS_SVSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/jobdata.hxx b/vcl/inc/jobdata.hxx new file mode 100644 index 000000000..714bcb381 --- /dev/null +++ b/vcl/inc/jobdata.hxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_JOBDATA_HXX +#define INCLUDED_VCL_JOBDATA_HXX + +#include "ppdparser.hxx" + +namespace psp { + +enum class orientation { + Portrait, + Landscape +}; + +struct VCL_DLLPUBLIC JobData +{ + int m_nCopies; + bool m_bCollate; + 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 languagelevel to use + int m_nColorDevice; // 0: no override, -1 grey scale, +1 color + int m_nPDFDevice; // 0: no override, -1 PostScript, +1: Automatically PDF, +2: Explicitly PDF + orientation m_eOrientation; + OUString m_aPrinterName; + bool m_bPapersizeFromSetup; + const PPDParser* m_pParser; + PPDContext m_aContext; + + JobData() : + m_nCopies( 1 ), + m_bCollate(false), + m_nLeftMarginAdjust( 0 ), + m_nRightMarginAdjust( 0 ), + m_nTopMarginAdjust( 0 ), + m_nBottomMarginAdjust( 0 ), + m_nColorDepth( 24 ), + m_nPSLevel( 0 ), + m_nColorDevice( 0 ), + m_nPDFDevice( 0 ), + m_eOrientation( orientation::Portrait ), + m_bPapersizeFromSetup( false ), + m_pParser( nullptr ) {} + + JobData& operator=(const psp::JobData& rRight); + + JobData( const JobData& rData ) { *this = rData; } + + void setCollate( bool bCollate ); + void setPaper( int nWidth, int nHeight ); // dimensions in pt + void setPaperBin( int nPaperBin ); + void resolveDefaultBackend(); + void setDefaultBackend(bool bUsePDF); + + // creates a new buffer using new + // it is up to the user to delete it again + bool getStreamBuffer( void*& pData, sal_uInt32& bytes ); + static bool constructFromStreamBuffer( const void* pData, sal_uInt32 bytes, JobData& rJobData ); +}; + +} // namespace + + +#endif // PSPRINT_JOBDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/jobset.h b/vcl/inc/jobset.h new file mode 100644 index 000000000..ce53c0541 --- /dev/null +++ b/vcl/inc/jobset.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_JOBSET_H +#define INCLUDED_VCL_INC_JOBSET_H + +#include +#include +#include +#include +#include + +// see com.sun.star.portal.client.JobSetupSystem.idl: +#define JOBSETUP_SYSTEM_WINDOWS 1 +#define JOBSETUP_SYSTEM_UNIX 3 +#define JOBSETUP_SYSTEM_MAC 4 + +class VCL_DLLPUBLIC ImplJobSetup +{ +private: + sal_uInt16 mnSystem; //< System - JOBSETUP_SYSTEM_xxxx + OUString maPrinterName; //< Printer-Name + OUString maDriver; //< Driver-Name + Orientation meOrientation; //< Orientation + DuplexMode meDuplexMode; //< Duplex + sal_uInt16 mnPaperBin; //< paper bin / in tray + Paper mePaperFormat; //< paper format + long mnPaperWidth; //< paper width (100th mm) + long mnPaperHeight; //< paper height (100th mm) + sal_uInt32 mnDriverDataLen; //< length of system specific data + sal_uInt8* mpDriverData; //< system specific data (will be streamed a byte block) + bool mbPapersizeFromSetup; + // setup mode + PrinterSetupMode meSetupMode; + // TODO: orig paper size + std::unordered_map< OUString, OUString > maValueMap; + +public: + ImplJobSetup(); + ImplJobSetup( const ImplJobSetup& rJobSetup ); + ~ImplJobSetup(); + + bool operator==( const ImplJobSetup& rImplJobSetup ) const; + + sal_uInt16 GetSystem() const { return mnSystem; } + void SetSystem(sal_uInt16 nSystem); + + const OUString& GetPrinterName() const { return maPrinterName; } + void SetPrinterName(const OUString& rPrinterName); + + const OUString& GetDriver() const { return maDriver; } + void SetDriver(const OUString& rDriver); + + Orientation GetOrientation() const { return meOrientation; } + void SetOrientation(Orientation eOrientation); + + DuplexMode GetDuplexMode() const { return meDuplexMode; } + void SetDuplexMode(DuplexMode eDuplexMode); + + sal_uInt16 GetPaperBin() const { return mnPaperBin; } + void SetPaperBin(sal_uInt16 nPaperBin); + + Paper GetPaperFormat() const { return mePaperFormat; } + void SetPaperFormat(Paper ePaperFormat); + + long GetPaperWidth() const { return mnPaperWidth; } + void SetPaperWidth(long nWidth); + + long GetPaperHeight() const { return mnPaperHeight; } + void SetPaperHeight(long nHeight); + + sal_uInt32 GetDriverDataLen() const { return mnDriverDataLen; } + void SetDriverDataLen(sal_uInt32 nDriverDataLen); + + const sal_uInt8* GetDriverData() const { return mpDriverData; } + void SetDriverData(sal_uInt8* pDriverData); + + bool GetPapersizeFromSetup() const { return mbPapersizeFromSetup; } + void SetPapersizeFromSetup(bool bPapersizeFromSetup); + + PrinterSetupMode GetPrinterSetupMode() const { return meSetupMode; } + void SetPrinterSetupMode(PrinterSetupMode eMode); + + const std::unordered_map< OUString, OUString >& GetValueMap() const + { return maValueMap; } + void SetValueMap(const OUString& rKey, const OUString& rValue); +}; + +// If paper format is PAPER_USER, in the system-independent part it will +// automatically be computed from paper width/height. +// If paper width/height is 0, in the system-independent part it will +// automatically be computed from paper format, if the latter is not PAPER_USER. + +#endif // INCLUDED_VCL_INC_JOBSET_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx b/vcl/inc/jsdialog/jsdialogbuilder.hxx new file mode 100644 index 000000000..d01521924 --- /dev/null +++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx @@ -0,0 +1,133 @@ +#ifndef INCLUDED_VCL_INC_JSDIALOG_JSDIALOG_HXX +#define INCLUDED_VCL_INC_JSDIALOG_JSDIALOG_HXX + +#include +#include +#include +#include +#include +#include +#include +#include + +class JSDialogSender +{ + VclPtr m_aOwnedToplevel; + +public: + JSDialogSender(VclPtr aOwnedToplevel) + : m_aOwnedToplevel(aOwnedToplevel) + { + } + + void notifyDialogState(); +}; + +class VCL_DLLPUBLIC JSInstanceBuilder : public SalInstanceBuilder +{ +public: + JSInstanceBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile); + virtual std::unique_ptr weld_dialog(const OString& id, + bool bTakeOwnership = true) override; + virtual std::unique_ptr weld_label(const OString& id, + bool bTakeOwnership = false) override; + virtual std::unique_ptr weld_button(const OString& id, + bool bTakeOwnership = false) override; + virtual std::unique_ptr weld_entry(const OString& id, + bool bTakeOwnership = false) override; + virtual std::unique_ptr weld_combo_box(const OString& id, + bool bTakeOwnership = false) override; + virtual std::unique_ptr weld_notebook(const OString& id, + bool bTakeOwnership = false) override; +}; + +template +class JSWidget : public BaseInstanceClass, public JSDialogSender +{ +public: + JSWidget(VclPtr aOwnedToplevel, VclClass* pObject, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : BaseInstanceClass(pObject, pBuilder, bTakeOwnership) + , JSDialogSender(aOwnedToplevel) + { + } + + virtual void show() override + { + BaseInstanceClass::show(); + notifyDialogState(); + } + + virtual void hide() override + { + BaseInstanceClass::hide(); + notifyDialogState(); + } + + virtual void set_sensitive(bool sensitive) override + { + BaseInstanceClass::set_sensitive(sensitive); + notifyDialogState(); + } +}; + +class VCL_DLLPUBLIC JSLabel : public JSWidget +{ +public: + JSLabel(VclPtr aOwnedToplevel, FixedText* pLabel, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + virtual void set_label(const OUString& rText) override; +}; + +class VCL_DLLPUBLIC JSButton : public JSWidget +{ +public: + JSButton(VclPtr aOwnedToplevel, ::Button* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); +}; + +class VCL_DLLPUBLIC JSEntry : public JSWidget +{ +public: + JSEntry(VclPtr aOwnedToplevel, ::Edit* pEntry, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + virtual void set_text(const OUString& rText) override; +}; + +class VCL_DLLPUBLIC JSListBox : public JSWidget +{ +public: + JSListBox(VclPtr aOwnedToplevel, ::ListBox* pListBox, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + virtual void insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) override; + virtual void remove(int pos) override; +}; + +class VCL_DLLPUBLIC JSComboBox : public JSWidget +{ +public: + JSComboBox(VclPtr aOwnedToplevel, ::ComboBox* pComboBox, + SalInstanceBuilder* pBuilder, bool bTakeOwnership); + virtual void insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) override; + virtual void remove(int pos) override; + virtual void set_entry_text(const OUString& rText) override; +}; + +class VCL_DLLPUBLIC JSNotebook : public JSWidget +{ +public: + JSNotebook(VclPtr aOwnedToplevel, ::TabControl* pControl, + SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_current_page(int nPage) override; + + virtual void set_current_page(const OString& rIdent) override; + + virtual void remove_page(const OString& rIdent) override; + + virtual void insert_page(const OString& rIdent, const OUString& rLabel, int nPos) override; +}; + +#endif diff --git a/vcl/inc/langboost.hxx b/vcl/inc/langboost.hxx new file mode 100644 index 000000000..84bdb2d84 --- /dev/null +++ b/vcl/inc/langboost.hxx @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef INCLUDED_VCL_INC_LANGBOOST_HXX +#define INCLUDED_VCL_INC_LANGBOOST_HXX + +namespace vcl +{ + const char* getLangBoost(); +} + +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/listbox.hxx b/vcl/inc/listbox.hxx new file mode 100644 index 000000000..1e4512eef --- /dev/null +++ b/vcl/inc/listbox.hxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_LISTBOX_HXX +#define INCLUDED_VCL_INC_LISTBOX_HXX + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +class ScrollBar; +class ScrollBarBox; + +#define HORZ_SCROLL 4 +#define IMG_TXT_DISTANCE 6 + +enum LB_EVENT_TYPE +{ + LET_MBDOWN, + LET_TRACKING, + LET_KEYMOVE, + LET_KEYSPACE +}; + +struct ImplEntryType +{ + OUString maStr; + SalLayoutGlyphs maStrGlyphs; + Image maImage; + void* mpUserData; + bool mbIsSelected; + ListBoxEntryFlags mnFlags; + long mnHeight; + + long getHeightWithMargin() const; + + ImplEntryType( const OUString& rStr, const Image& rImage ) : + maStr( rStr ), + maImage( rImage ), + mnFlags( ListBoxEntryFlags::NONE ), + mnHeight( 0 ) + { + mbIsSelected = false; + mpUserData = nullptr; + } + + ImplEntryType( const OUString& rStr ) : + maStr( rStr ), + mnFlags( ListBoxEntryFlags::NONE ), + mnHeight( 0 ) + { + mbIsSelected = false; + mpUserData = nullptr; + } + + /// Computes maStr's text layout (glyphs), cached in maStrGlyphs. + SalLayoutGlyphs* GetTextGlyphs(const OutputDevice* pOutputDevice); +}; + +class ImplEntryList +{ +private: + VclPtr mpWindow; ///< For getting the current locale when matching strings + sal_Int32 mnLastSelected; + sal_Int32 mnSelectionAnchor; + sal_Int32 mnImages; + + sal_Int32 mnMRUCount; + sal_Int32 mnMaxMRUCount; + + Link maSelectionChangedHdl; + bool mbCallSelectionChangedHdl; + std::vector > maEntries; + + ImplEntryType* GetEntry( sal_Int32 nPos ) const + { + if (nPos < 0 || o3tl::make_unsigned(nPos) >= maEntries.size()) + return nullptr; + return maEntries[nPos].get(); + } + +public: + ImplEntryList( vcl::Window* pWindow ); + ~ImplEntryList(); + + sal_Int32 InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort ); + void RemoveEntry( sal_Int32 nPos ); + const ImplEntryType* GetEntryPtr( sal_Int32 nPos ) const { return GetEntry( nPos ); } + ImplEntryType* GetMutableEntryPtr( sal_Int32 nPos ) const { return GetEntry( nPos ); } + void Clear(); + + sal_Int32 FindMatchingEntry( const OUString& rStr, sal_Int32 nStart, bool bLazy ) const; + sal_Int32 FindEntry( const OUString& rStr, bool bSearchMRUArea = false ) const; + + /// helper: add up heights up to index nEndIndex. + /// GetAddedHeight( 0 ) @return 0 + /// GetAddedHeight( LISTBOX_ENTRY_NOTFOUND ) @return 0 + /// GetAddedHeight( i, k ) with k > i is equivalent -GetAddedHeight( k, i ) + long GetAddedHeight( sal_Int32 nEndIndex, sal_Int32 nBeginIndex ) const; + long GetEntryHeight( sal_Int32 nPos ) const; + + sal_Int32 GetEntryCount() const { return static_cast(maEntries.size()); } + bool HasImages() const { return mnImages != 0; } + + OUString GetEntryText( sal_Int32 nPos ) const; + + bool HasEntryImage( sal_Int32 nPos ) const; + Image GetEntryImage( sal_Int32 nPos ) const; + + void SetEntryData( sal_Int32 nPos, void* pNewData ); + void* GetEntryData( sal_Int32 nPos ) const; + + void SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags ); + + void SelectEntry( sal_Int32 nPos, bool bSelect ); + + sal_Int32 GetSelectedEntryCount() const; + OUString GetSelectedEntry( sal_Int32 nIndex ) const; + sal_Int32 GetSelectedEntryPos( sal_Int32 nIndex ) const; + bool IsEntryPosSelected( sal_Int32 nIndex ) const; + + void SetLastSelected( sal_Int32 nPos ) { mnLastSelected = nPos; } + sal_Int32 GetLastSelected() const { return mnLastSelected; } + + void SetSelectionAnchor( sal_Int32 nPos ) { mnSelectionAnchor = nPos; } + sal_Int32 GetSelectionAnchor() const { return mnSelectionAnchor; } + + void SetSelectionChangedHdl( const Link& rLnk ) { maSelectionChangedHdl = rLnk; } + void SetCallSelectionChangedHdl( bool bCall ) { mbCallSelectionChangedHdl = bCall; } + + void SetMRUCount( sal_Int32 n ) { mnMRUCount = n; } + sal_Int32 GetMRUCount() const { return mnMRUCount; } + + void SetMaxMRUCount( sal_Int32 n ) { mnMaxMRUCount = n; } + sal_Int32 GetMaxMRUCount() const { return mnMaxMRUCount; } + + /** An Entry is selectable if its mnFlags does not have the + ListBoxEntryFlags::DisableSelection flag set. */ + bool IsEntrySelectable( sal_Int32 nPos ) const; + + /** @return 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. + */ + sal_Int32 FindFirstSelectable( sal_Int32 nPos, bool bForward = true ); +}; + +class ImplListBoxWindow : public Control, public vcl::ISearchableStringList +{ +private: + std::unique_ptr mpEntryList; ///< EntryList + tools::Rectangle maFocusRect; + + Size maUserItemSize; + + long mnMaxTxtHeight; ///< Maximum height of a text item + long mnMaxTxtWidth; ///< Maximum width of a text item + ///< Entry without Image + long mnMaxImgTxtWidth;///< Maximum width of a text item + ///< Entry AND Image + long mnMaxImgWidth; ///< Maximum width of an image item + long mnMaxImgHeight; ///< Maximum height of an image item + long mnMaxWidth; ///< Maximum width of an entry + long mnMaxHeight; ///< Maximum height of an entry + + sal_Int32 mnCurrentPos; ///< Position (Focus) + sal_Int32 mnTrackingSaveSelection; ///< Selection before Tracking(); + + std::set< sal_Int32 > maSeparators; ///< Separator positions + + sal_Int32 mnUserDrawEntry; + + sal_Int32 mnTop; ///< output from line on + long mnLeft; ///< output from column on + long mnTextHeight; ///< text height + + sal_uInt16 mnSelectModifier; ///< Modifiers + + bool mbHasFocusRect : 1; + bool mbSort : 1; ///< ListBox sorted + bool mbTrack : 1; ///< Tracking + bool mbMulti : 1; ///< MultiListBox + bool mbStackMode : 1; ///< StackSelection + bool mbSimpleMode : 1; ///< SimpleMode for MultiListBox + bool mbTravelSelect : 1; ///< TravelSelect + bool mbTrackingSelect : 1; ///< Selected at a MouseMove + bool mbSelectionChanged : 1; ///< Do not call Select() too often ... + bool mbMouseMoveSelect : 1; ///< Select at MouseMove + bool mbGrabFocus : 1; ///< Grab focus at MBDown + bool mbUserDrawEnabled : 1; ///< UserDraw possible + bool mbInUserDraw : 1; ///< In UserDraw + bool mbReadOnly : 1; ///< ReadOnly + bool mbMirroring : 1; ///< pb: #106948# explicit mirroring for calc + bool mbCenter : 1; ///< center Text output + bool mbRight : 1; ///< right align Text output + bool mbEdgeBlending : 1; + /// Listbox is actually a dropdown (either combobox, or popup window treated as dropdown) + bool mbIsDropdown : 1; + + Link maScrollHdl; + Link maSelectHdl; + Link maCancelHdl; + Link maDoubleClickHdl; + Link maUserDrawHdl; + Link maMRUChangedHdl; + Link maFocusHdl; + Link maListItemSelectHdl; + + vcl::QuickSelectionEngine maQuickSelectionEngine; + +protected: + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void Resize() override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + + bool SelectEntries( sal_Int32 nSelect, LB_EVENT_TYPE eLET, bool bShift = false, bool bCtrl = false, bool bSelectPosChange = false ); + void ImplPaint(vcl::RenderContext& rRenderContext, sal_Int32 nPos); + void ImplDoPaint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void ImplCalcMetrics(); + void ImplUpdateEntryMetrics( ImplEntryType& rEntry ); + void ImplCallSelect(); + + void ImplShowFocusRect(); + void ImplHideFocusRect(); + + virtual void StateChanged( StateChangedType nType ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + +public: + virtual void FillLayoutData() const override; + + ImplListBoxWindow( vcl::Window* pParent, WinBits nWinStyle ); + virtual ~ImplListBoxWindow() override; + virtual void dispose() override; + + ImplEntryList* GetEntryList() const { return mpEntryList.get(); } + + sal_Int32 InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry ); // sorts using mbSort + sal_Int32 InsertEntry( sal_Int32 nPos, ImplEntryType* pNewEntry, bool bSort ); // to insert ignoring mbSort, e.g. mru + void RemoveEntry( sal_Int32 nPos ); + void Clear(); + void ResetCurrentPos() { mnCurrentPos = LISTBOX_ENTRY_NOTFOUND; } + sal_Int32 GetCurrentPos() const { return mnCurrentPos; } + sal_uInt16 GetDisplayLineCount() const; + void SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags ); + + void DrawEntry(vcl::RenderContext& rRenderContext, sal_Int32 nPos, bool bDrawImage, bool bDrawText); + + void SelectEntry( sal_Int32 nPos, bool bSelect ); + void DeselectAll(); + sal_Int32 GetEntryPosForPoint( const Point& rPoint ) const; + sal_Int32 GetLastVisibleEntry() const; + + bool ProcessKeyInput( const KeyEvent& rKEvt ); + + void SetTopEntry( sal_Int32 nTop ); + sal_Int32 GetTopEntry() const { return mnTop; } + /** ShowProminentEntry will set the entry corresponding to nEntryPos + either at top or in the middle depending on the chosen style*/ + void ShowProminentEntry( sal_Int32 nEntryPos ); + using Window::IsVisible; + bool IsVisible( sal_Int32 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; } + + /** + * Removes existing separators, and sets the position of the + * one and only separator. + */ + void SetSeparatorPos( sal_Int32 n ); + /** + * Gets the position of the separator which was added first. + * Returns LISTBOX_ENTRY_NOTFOUND if there is no separator. + */ + sal_Int32 GetSeparatorPos() const; + + /** + * Adds a new separator at the given position n. + */ + void AddSeparator( sal_Int32 n ) { maSeparators.insert( n ); } + /** + * Checks if the given number n is an element of the separator positions set. + */ + bool isSeparator( const sal_Int32 &n ) const; + + void SetTravelSelect( bool bTravelSelect ) { mbTravelSelect = bTravelSelect; } + bool IsTravelSelect() const { return mbTravelSelect; } + bool IsTrackingSelect() const { return mbTrackingSelect; } + + void SetUserItemSize( const Size& rSz ); + + 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; } + + void EnableMouseMoveSelect( bool bMouseMoveSelect ) { mbMouseMoveSelect = bMouseMoveSelect; } + bool IsMouseMoveSelect() const { return mbMouseMoveSelect||mbStackMode; } + + Size CalcSize(sal_Int32 nMaxLines) const; + tools::Rectangle GetBoundingRectangle( sal_Int32 nItem ) const; + + long GetEntryHeight() const { return mnMaxHeight; } + long GetEntryHeightWithMargin() const; + long GetMaxEntryWidth() const { return mnMaxWidth; } + + void SetScrollHdl( const Link& rLink ) { maScrollHdl = rLink; } + void SetSelectHdl( const Link& rLink ) { maSelectHdl = rLink; } + void SetCancelHdl( const Link& rLink ) { maCancelHdl = rLink; } + void SetDoubleClickHdl( const Link& rLink ) { maDoubleClickHdl = rLink; } + void SetUserDrawHdl( const Link& rLink ) { maUserDrawHdl = rLink; } + void SetMRUChangedHdl( const Link& rLink ) { maMRUChangedHdl = rLink; } + void SetFocusHdl( const Link& rLink ) { maFocusHdl = rLink ; } + + void SetListItemSelectHdl( const Link& rLink ) { maListItemSelectHdl = rLink ; } + bool IsSelectionChanged() const { return mbSelectionChanged; } + sal_uInt16 GetSelectModifier() const { return mnSelectModifier; } + + void EnableSort( bool b ) { mbSort = b; } + + void SetReadOnly( bool bReadOnly ) { mbReadOnly = bReadOnly; } + bool IsReadOnly() const { return mbReadOnly; } + + DrawTextFlags ImplGetTextStyle() const; + + /// pb: #106948# explicit mirroring for calc + void EnableMirroring() { mbMirroring = true; } + bool IsMirroring() const { return mbMirroring; } + + bool GetEdgeBlending() const { return mbEdgeBlending; } + void SetEdgeBlending(bool bNew) { mbEdgeBlending = bNew; } + + using Control::ImplInitSettings; + virtual void ApplySettings(vcl::RenderContext& rRenderContext) override; + +protected: + // ISearchableStringList + virtual vcl::StringEntryIdentifier CurrentEntry( OUString& _out_entryText ) const override; + virtual vcl::StringEntryIdentifier NextEntry( vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const override; + virtual void SelectEntry( vcl::StringEntryIdentifier _entry ) override; +}; + +class ImplListBox : public Control +{ +private: + VclPtr maLBWindow; + VclPtr mpHScrollBar; + VclPtr mpVScrollBar; + VclPtr mpScrollBarBox; + + bool mbVScroll : 1; // VScroll on or off + bool mbHScroll : 1; // HScroll on or off + bool mbAutoHScroll : 1; // AutoHScroll on or off + bool mbEdgeBlending : 1; + + Link maScrollHdl; // because it is needed by ImplListBoxWindow itself + +protected: + virtual void GetFocus() override; + virtual void StateChanged( StateChangedType nType ) override; + + virtual bool EventNotify( NotifyEvent& rNEvt ) override; + + void ImplResizeControls(); + void ImplCheckScrollBars(); + void ImplInitScrollBars(); + + DECL_LINK( ScrollBarHdl, ScrollBar*, void ); + DECL_LINK( LBWindowScrolled, ImplListBoxWindow*, void ); + DECL_LINK( MRUChanged, LinkParamNone*, void ); + +public: + ImplListBox( vcl::Window* pParent, WinBits nWinStyle ); + virtual ~ImplListBox() override; + virtual void dispose() override; + + const ImplEntryList* GetEntryList() const { return maLBWindow->GetEntryList(); } + ImplListBoxWindow* GetMainWindow() { return maLBWindow.get(); } + + virtual void Resize() override; + virtual const Wallpaper& GetDisplayBackground() const override; + + sal_Int32 InsertEntry( sal_Int32 nPos, const OUString& rStr ); + sal_Int32 InsertEntry( sal_Int32 nPos, const OUString& rStr, const Image& rImage ); + void RemoveEntry( sal_Int32 nPos ); + void SetEntryData( sal_Int32 nPos, void* pNewData ) { maLBWindow->GetEntryList()->SetEntryData( nPos, pNewData ); } + void Clear(); + + void SetEntryFlags( sal_Int32 nPos, ListBoxEntryFlags nFlags ); + + void SelectEntry( sal_Int32 nPos, bool bSelect ); + void SetNoSelection(); + void ResetCurrentPos() { maLBWindow->ResetCurrentPos(); } + sal_Int32 GetCurrentPos() const { return maLBWindow->GetCurrentPos(); } + + bool ProcessKeyInput( const KeyEvent& rKEvt ) { return maLBWindow->ProcessKeyInput( rKEvt ); } + bool HandleWheelAsCursorTravel( const CommandEvent& rCEvt ); + + /** + * Removes existing separators, and sets the position of the + * one and only separator. + */ + void SetSeparatorPos( sal_Int32 n ) { maLBWindow->SetSeparatorPos( n ); } + /** + * Gets the position of the separator which was added first. + * Returns LISTBOX_ENTRY_NOTFOUND if there is no separator. + */ + sal_Int32 GetSeparatorPos() const { return maLBWindow->GetSeparatorPos(); } + + /** + * Adds a new separator at the given position n. + */ + void AddSeparator( sal_Int32 n ) { maLBWindow->AddSeparator( n ); } + + void SetTopEntry( sal_Int32 nTop ) { maLBWindow->SetTopEntry( nTop ); } + sal_Int32 GetTopEntry() const { return maLBWindow->GetTopEntry(); } + void ShowProminentEntry( sal_Int32 nPos ) { maLBWindow->ShowProminentEntry( nPos ); } + using Window::IsVisible; + bool IsVisible( sal_Int32 nEntry ) const { return maLBWindow->IsVisible( nEntry ); } + + long GetLeftIndent() const { return maLBWindow->GetLeftIndent(); } + void SetLeftIndent( sal_uInt16 n ) { maLBWindow->SetLeftIndent( n ); } + + 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 ); } + + void SetReadOnly( bool b ) { maLBWindow->SetReadOnly( b ); } + bool IsReadOnly() const { return maLBWindow->IsReadOnly(); } + + Size CalcSize( sal_Int32 nMaxLines ) const { return maLBWindow->CalcSize( nMaxLines ); } + long GetEntryHeight() const { return maLBWindow->GetEntryHeight(); } + long GetEntryHeightWithMargin() const{ return maLBWindow->GetEntryHeightWithMargin(); } + long GetMaxEntryWidth() const { return maLBWindow->GetMaxEntryWidth(); } + + void SetScrollHdl( const Link& rLink ) { maScrollHdl = rLink; } + void SetSelectHdl( const Link& rLink ) { maLBWindow->SetSelectHdl( rLink ); } + void SetCancelHdl( const Link& rLink ) { maLBWindow->SetCancelHdl( rLink ); } + void SetDoubleClickHdl( const Link& rLink ) { maLBWindow->SetDoubleClickHdl( rLink ); } + void SetUserDrawHdl( const Link& rLink ) { maLBWindow->SetUserDrawHdl( rLink ); } + void SetFocusHdl( const Link& rLink ) { maLBWindow->SetFocusHdl( rLink ); } + void SetListItemSelectHdl( const Link& rLink ) { maLBWindow->SetListItemSelectHdl( rLink ); } + void SetSelectionChangedHdl( const Link& rLnk ) { maLBWindow->GetEntryList()->SetSelectionChangedHdl( rLnk ); } + void SetCallSelectionChangedHdl( bool bCall ) { maLBWindow->GetEntryList()->SetCallSelectionChangedHdl( bCall ); } + bool IsSelectionChanged() const { return maLBWindow->IsSelectionChanged(); } + sal_uInt16 GetSelectModifier() const { return maLBWindow->GetSelectModifier(); } + + void SetMRUEntries( const OUString& rEntries, sal_Unicode cSep ); + OUString GetMRUEntries( sal_Unicode cSep ) const; + void SetMaxMRUCount( sal_Int32 n ) { maLBWindow->GetEntryList()->SetMaxMRUCount( n ); } + sal_Int32 GetMaxMRUCount() const { return maLBWindow->GetEntryList()->GetMaxMRUCount(); } + sal_uInt16 GetDisplayLineCount() const + { return maLBWindow->GetDisplayLineCount(); } + + bool GetEdgeBlending() const { return mbEdgeBlending; } + void SetEdgeBlending(bool bNew); + + /// pb: #106948# explicit mirroring for calc + void EnableMirroring() { maLBWindow->EnableMirroring(); } +}; + +class ImplListBoxFloatingWindow : public FloatingWindow +{ +private: + VclPtr mpImplLB; + Size maPrefSz; + sal_uInt16 mnDDLineCount; + sal_Int32 mnPopupModeStartSaveSelection; + bool mbAutoWidth; + +protected: + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + +public: + ImplListBoxFloatingWindow( vcl::Window* pParent ); + virtual ~ImplListBoxFloatingWindow() override; + virtual void dispose() override; + 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; } + + Size CalcFloatSize(); + void StartFloat( bool bStartTracking ); + + virtual void setPosSizePixel( long nX, long nY, + long nWidth, long nHeight, PosSizeFlags nFlags = PosSizeFlags::All ) override; + + void SetDropDownLineCount( sal_uInt16 n ) { mnDDLineCount = n; } + sal_uInt16 GetDropDownLineCount() const { return mnDDLineCount; } + + sal_Int32 GetPopupModeStartSaveSelection() const { return mnPopupModeStartSaveSelection; } + + virtual void Resize() override; +}; + +class ImplWin : public Control +{ +private: + + sal_Int32 mnItemPos; ///< because of UserDraw I have to know which item I draw + OUString maString; + Image maImage; + + tools::Rectangle maFocusRect; + + Link maMBDownHdl; + + bool mbEdgeBlending : 1; + + void ImplDraw(vcl::RenderContext& rRenderContext, bool bLayout = false); +protected: + virtual void FillLayoutData() const override; + +public: + ImplWin( vcl::Window* pParent, WinBits nWinStyle ); + + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual void Resize() override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + sal_Int32 GetItemPos() const { return mnItemPos; } + void SetItemPos( sal_Int32 n ) { mnItemPos = n; } + + void SetString( const OUString& rStr ) { maString = rStr; } + + void SetImage( const Image& rImg ) { maImage = rImg; } + + void SetMBDownHdl( const Link& rLink ) { maMBDownHdl = rLink; } + + void DrawEntry(vcl::RenderContext& rRenderContext, bool bLayout); + + bool GetEdgeBlending() const { return mbEdgeBlending; } + void SetEdgeBlending(bool bNew) { mbEdgeBlending = bNew; } + + virtual void ShowFocus(const tools::Rectangle& rRect) override; + + using Control::ImplInitSettings; + virtual void ApplySettings(vcl::RenderContext& rRenderContext) override; + +}; + +class ImplBtn : public PushButton +{ +private: + Link maMBDownHdl; + +public: + ImplBtn( vcl::Window* pParent, WinBits nWinStyle ); + + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + void SetMBDownHdl( const Link& rLink ) { maMBDownHdl = rLink; } +}; + +void ImplInitDropDownButton( PushButton* pButton ); + +#endif // INCLUDED_VCL_INC_LISTBOX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/messagedialog.hxx b/vcl/inc/messagedialog.hxx new file mode 100644 index 000000000..679767be7 --- /dev/null +++ b/vcl/inc/messagedialog.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_MESSAGEDIALOG_HXX +#define INCLUDED_VCL_INC_MESSAGEDIALOG_HXX + +#include +#include +#include + +class MessageDialog : public Dialog +{ +private: + VclButtonsType m_eButtonsType; + VclMessageType m_eMessageType; + VclPtr m_pOwnedContentArea; + VclPtr m_pOwnedActionArea; + VclPtr m_pGrid; + VclPtr m_pMessageBox; + VclPtr m_pImage; + VclPtr m_pPrimaryMessage; + VclPtr m_pSecondaryMessage; + OUString m_sPrimaryString; + OUString m_sSecondaryString; + void create_owned_areas(); + + static void SetMessagesWidths(vcl::Window const* pParent, VclMultiLineEdit* pPrimaryMessage, + VclMultiLineEdit* pSecondaryMessage); + + friend class VclPtr; + MessageDialog(vcl::Window* pParent, WinBits nStyle); + + virtual void StateChanged(StateChangedType nType) override; + +public: + MessageDialog(vcl::Window* pParent, const OUString& rMessage, VclMessageType eMessageType, + VclButtonsType eButtonsType); + virtual bool set_property(const OString& rKey, const OUString& rValue) override; + OUString const& get_primary_text() const; + OUString const& get_secondary_text() const; + void set_primary_text(const OUString& rPrimaryString); + void set_secondary_text(const OUString& rSecondaryString); + virtual ~MessageDialog() override; + virtual void dispose() override; + + void create_message_area(); + VclContainer* get_message_area() const { return m_pMessageBox.get(); } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/BufferObject.hxx b/vcl/inc/opengl/BufferObject.hxx new file mode 100644 index 000000000..396de89de --- /dev/null +++ b/vcl/inc/opengl/BufferObject.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H +#define INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H + +namespace vcl +{ + +template +class BufferObject +{ +private: + GLuint mId; + +public: + BufferObject() + : mId(0) + { + glGenBuffers(1, &mId); + CHECK_GL_ERROR(); + } + + virtual ~BufferObject() + { + if (mId) + { + glDeleteBuffers(1, &mId); + CHECK_GL_ERROR(); + mId = 0; + } + } + + void bind() + { + if (mId) + { + glBindBuffer(BUFFER_TYPE, mId); + CHECK_GL_ERROR(); + } + } + + void unbind() + { + if (mId) + { + glBindBuffer(BUFFER_TYPE, 0); + CHECK_GL_ERROR(); + } + } + + void upload(const std::vector& rData) + { + if (mId) + { + bind(); + glBufferData(BUFFER_TYPE, sizeof(TYPE) * rData.size(), rData.data(), GL_STATIC_DRAW); + CHECK_GL_ERROR(); + } + } + +}; + +template +class VertexBufferObject final : public BufferObject +{ +}; + +class IndexBufferObject final : public BufferObject +{ +}; + +} // end vcl + +#endif // INCLUDED_VCL_INC_OPENGL_BUFFEROBJECT_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/DeviceInfo.hxx b/vcl/inc/opengl/DeviceInfo.hxx new file mode 100644 index 000000000..b0ad3a6cf --- /dev/null +++ b/vcl/inc/opengl/DeviceInfo.hxx @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_DEVICEINFO_HXX +#define INCLUDED_VCL_INC_OPENGL_DEVICEINFO_HXX + +class OpenGLDeviceInfo +{ +public: + virtual ~OpenGLDeviceInfo() = 0; + + virtual bool isDeviceBlocked() = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/FixedTextureAtlas.hxx b/vcl/inc/opengl/FixedTextureAtlas.hxx new file mode 100644 index 000000000..e576fcb54 --- /dev/null +++ b/vcl/inc/opengl/FixedTextureAtlas.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_FIXEDTEXTUREATLAS_HXX +#define INCLUDED_VCL_INC_OPENGL_FIXEDTEXTUREATLAS_HXX + +#include +#include + +struct FixedTexture; + +class FixedTextureAtlasManager final +{ + std::vector> maFixedTextures; + + int mWidthFactor; + int mHeightFactor; + int mSubTextureSize; + + void CreateNewTexture(); + + FixedTextureAtlasManager( const FixedTextureAtlasManager& ) = delete; + FixedTextureAtlasManager& operator=( const FixedTextureAtlasManager& ) = delete; + +public: + FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nTextureSize); + ~FixedTextureAtlasManager(); + + OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData); + OpenGLTexture Reserve(int nWidth, int nHeight); + + int GetSubtextureSize() const + { + return mSubTextureSize; + } +}; + +#endif // INCLUDED_VCL_INC_OPENGL_FIXEDTEXTUREATLAS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/LineRenderUtils.hxx b/vcl/inc/opengl/LineRenderUtils.hxx new file mode 100644 index 000000000..8d97fa3ee --- /dev/null +++ b/vcl/inc/opengl/LineRenderUtils.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H +#define INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H + +#include + +namespace vcl +{ +class LineBuilder +{ +private: + std::vector& mrVertices; + std::vector& mrIndices; + GLubyte mR, mG, mB, mA; + GLfloat mfLineWidth; + GLfloat mfLineWidthAndAA; + size_t mnInitialIndexSize; + bool mbIncomplete; + +public: + LineBuilder(std::vector& rVertices, std::vector& rIndices, + Color nColor, GLfloat fTransparency, + GLfloat fLineWidth, bool bUseAA); + + void appendLineSegment(const glm::vec2& rPoint1, const glm::vec2& rNormal1, GLfloat aExtrusion1, + const glm::vec2& rPoint2, const glm::vec2& rNormal2, GLfloat aExtrusion2); + + void appendLine(const glm::vec2& rPoint1, const glm::vec2& rPoint2); + + void appendAndConnectLinePoint(const glm::vec2& rPoint, const glm::vec2& aNormal, GLfloat aExtrusion); + + void appendMiterJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + glm::vec2 const& nextLineVector); + void appendBevelJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + const glm::vec2& nextLineVector); + void appendRoundJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + const glm::vec2& nextLineVector); + void appendRoundLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2); + void appendSquareLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2); +}; + +} // end vcl + +#endif // INCLUDED_VCL_INC_OPENGL_LINERENDERUTILS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/PackedTextureAtlas.hxx b/vcl/inc/opengl/PackedTextureAtlas.hxx new file mode 100644 index 000000000..7a283aa45 --- /dev/null +++ b/vcl/inc/opengl/PackedTextureAtlas.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX +#define INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX + +#include +#include + +struct PackedTexture; + +/** + * Pack textures into one texture atlas. + * + * This is based on algorithm described in [1] and is an + * adaptation of "texture atlas generator" from [2]. + * + * [1]: http://www.blackpawn.com/texts/lightmaps/ + * [2]: https://github.com/lukaszdk/texture-atlas-generator + * + */ +class VCL_DLLPUBLIC PackedTextureAtlasManager final +{ + std::vector> maPackedTextures; + + int mnTextureWidth; + int mnTextureHeight; + + void CreateNewTexture(); + + PackedTextureAtlasManager( const PackedTextureAtlasManager& ) = delete; + PackedTextureAtlasManager& operator=( const PackedTextureAtlasManager& ) = delete; + +public: + + /** + * nTextureWidth and nTextureHeight are the dimensions of the common texture(s) + * nTextureLimit is the maximum limit of that a texture atlas can have (0 or less - unlimited) + */ + PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight); + ~PackedTextureAtlasManager(); + + OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData); + OpenGLTexture Reserve(int nWidth, int nHeight); + std::vector ReduceTextureNumber(int nMaxNumberOfTextures); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_PACKEDTEXTUREATLAS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/RenderList.hxx b/vcl/inc/opengl/RenderList.hxx new file mode 100644 index 000000000..213a2f43b --- /dev/null +++ b/vcl/inc/opengl/RenderList.hxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_RENDERLIST_H +#define INCLUDED_VCL_INC_OPENGL_RENDERLIST_H + +#include + +#include + +#include +#include +#include + +#include + +#include + +struct Vertex +{ + glm::vec2 position; + glm::vec4 color; + glm::vec4 lineData; +}; + +static_assert(sizeof(Vertex) == (2*4 + 4*4 + 4*4), "Vertex struct has wrong size/alignment"); + + +struct RenderParameters +{ + std::vector maVertices; + std::vector maIndices; +}; + +struct RenderTextureParameters +{ + std::vector maVertices; + std::vector maTextureCoords; + std::vector maColors; + OpenGLTexture maTexture; +}; + +struct RenderEntry +{ + basegfx::B2DRange maOverlapTrackingRectangle; + + RenderParameters maTriangleParameters; + RenderParameters maLineParameters; + + std::unordered_map maTextureParametersMap; + + bool hasTriangles() const + { + return !maTriangleParameters.maVertices.empty(); + } + + bool hasLines() const + { + return !maLineParameters.maVertices.empty(); + } + + bool hasTextures() const + { + return !maTextureParametersMap.empty(); + } +}; + +class RenderList +{ +private: + std::vector maRenderEntries; + std::vector maRectangles; + + bool doesOverlap(const basegfx::B2DRange& rDrawRectangle) + { + if (!maRenderEntries.back().maOverlapTrackingRectangle.overlaps(rDrawRectangle)) + return false; + + for (const basegfx::B2DRange& rRectangle : maRectangles) + { + if (rRectangle.overlaps(rDrawRectangle)) + return true; + } + return false; + } + + void checkOverlapping(const basegfx::B2DRange& rDrawRectangle) + { + if (maRenderEntries.empty() || doesOverlap(rDrawRectangle)) + { + maRenderEntries.emplace_back(); + maRenderEntries.back().maOverlapTrackingRectangle = rDrawRectangle; + + maRectangles.clear(); + maRectangles.reserve(30); + maRectangles.push_back(rDrawRectangle); + } + else + { + maRenderEntries.back().maOverlapTrackingRectangle.expand(rDrawRectangle); + + if (maRectangles.size() < 30) + { + maRectangles.push_back(rDrawRectangle); + } + else + { + basegfx::B2DRange aTempRectangle(maRectangles[0]); + aTempRectangle.expand(rDrawRectangle); + double minArea = aTempRectangle.getWidth() * aTempRectangle.getHeight(); + size_t index = 0; + + double area; + for (size_t i = 1; i < maRectangles.size(); ++i) + { + aTempRectangle = maRectangles[i]; + aTempRectangle.expand(rDrawRectangle); + area = aTempRectangle.getWidth() * aTempRectangle.getHeight(); + if (area < minArea) + index = i; + } + maRectangles[index].expand(rDrawRectangle); + } + } + } + +public: + + RenderList() = default; + + bool empty() + { + return maRenderEntries.empty(); + } + + void clear() + { + maRenderEntries.clear(); + } + + std::vector& getEntries() + { + return maRenderEntries; + } + + VCL_DLLPUBLIC void addDrawTextureWithMaskColor(OpenGLTexture const & rTexture, Color nColor, const SalTwoRect& r2Rect); + + void addDrawPixel(long nX, long nY, Color nColor); + + void addDrawRectangle(long nX, long nY, long nWidth, long nHeight, double fTransparency, + Color nLineColor, Color nFillColor); + + void addDrawLine(long nX1, long nY1, long nX2, long nY2, Color nLineColor, bool bUseAA); + + void addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency, + Color nLineColor, Color nFillColor, bool bUseAA); + + void addDrawPolyLine(const basegfx::B2DPolygon& rPolygon, double fTransparency, + double fLineWidth, basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, double fMiterMinimumAngle, + Color nLineColor, bool bUseAA); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_RENDERLIST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/RenderState.hxx b/vcl/inc/opengl/RenderState.hxx new file mode 100644 index 000000000..3a89344e2 --- /dev/null +++ b/vcl/inc/opengl/RenderState.hxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_RENDER_STATE_H +#define INCLUDED_VCL_INC_OPENGL_RENDER_STATE_H + +#include + +template +class GenericCapabilityState +{ +protected: + bool mbTest; + + GenericCapabilityState() + : mbTest(false) + { + } + + static bool readState() + { + return glIsEnabled(ENUM_TYPE); + } + +public: + void sync() + { + mbTest = readState(); + } + + void enable() + { + if (!mbTest) + { + glEnable(ENUM_TYPE); + CHECK_GL_ERROR(); + mbTest = true; + } + else + { + VCL_GL_INFO(TYPE::className() << ": enable called but already enabled"); + } +#ifdef DBG_UTIL + checkState(); +#endif + } + + void disable() + { + if (mbTest) + { + glDisable(ENUM_TYPE); + CHECK_GL_ERROR(); + mbTest = false; + } + else + { + VCL_GL_INFO(TYPE::className() << ": disable called but already disabled"); + } +#ifdef DBG_UTIL + checkState(); +#endif + } + +#ifdef DBG_UTIL + void checkState() + { + bool bRealState = readState(); + if (mbTest != bRealState) + { + VCL_GL_INFO(TYPE::className() << " mismatch! " + << "Expected: " << (mbTest ? "enabled" : "disabled") + << " but is: " << (bRealState ? "enabled" : "disabled")); + } + } +#endif +}; + +class ScissorState : public GenericCapabilityState +{ +private: + int mX; + int mY; + int mWidth; + int mHeight; + +public: + static std::string className() { return std::string("ScissorState"); } + + ScissorState() + : mX(0) + , mY(0) + , mWidth(0) + , mHeight(0) + {} + + void set(int x, int y, int width, int height) + { + if (x != mX || y != mY || width != mWidth || height != mHeight) + { + glScissor(x, y, width, height); + CHECK_GL_ERROR(); + + mX = x; + mY = y; + mWidth = width; + mHeight = height; + } + } +}; + +class StencilState : public GenericCapabilityState +{ +public: + static std::string className() { return std::string("StencilState"); } +}; + +class BlendState : public GenericCapabilityState +{ + GLenum mnSourceMode; + GLenum mnDestinationMode; +public: + BlendState() + : mnSourceMode(GL_ZERO) + , mnDestinationMode(GL_ZERO) + {} + + static std::string className() { return std::string("BlendState"); } + + void func(GLenum nSource, GLenum nDestination) + { + if (mnSourceMode != nSource || mnDestinationMode != nDestination) + { + glBlendFunc(nSource, nDestination); + CHECK_GL_ERROR(); + mnSourceMode = nSource; + mnDestinationMode = nDestination; + } + } +}; + +class RenderState +{ + TextureState maTexture; + ScissorState maScissor; + StencilState maStencil; + BlendState maBlend; + + tools::Rectangle maCurrentViewport; + +public: + RenderState() + {} + + void viewport(tools::Rectangle aViewPort) + { + if (aViewPort != maCurrentViewport) + { + glViewport(aViewPort.Left(), aViewPort.Top(), aViewPort.GetWidth(), aViewPort.GetHeight()); + CHECK_GL_ERROR(); + maCurrentViewport = aViewPort; + } + } + + TextureState& texture() { return maTexture; } + ScissorState& scissor() { return maScissor; } + StencilState& stencil() { return maStencil; } + BlendState& blend() { return maBlend; } + + void sync() + { + VCL_GL_INFO("RenderState::sync"); + maScissor.sync(); + maStencil.sync(); + maBlend.sync(); + } +}; + +#endif // INCLUDED_VCL_INC_OPENGL_RENDER_STATE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/TextureState.hxx b/vcl/inc/opengl/TextureState.hxx new file mode 100644 index 000000000..fbf2b9cee --- /dev/null +++ b/vcl/inc/opengl/TextureState.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_TEXTURE_STATE_H +#define INCLUDED_VCL_INC_OPENGL_TEXTURE_STATE_H + +#include + +class TextureState +{ +private: + GLuint mnCurrentTextureUnit; + std::vector maBoundTextures; + +public: + TextureState() + : mnCurrentTextureUnit(0) + , maBoundTextures(4, 0) + {} + + static void generate(GLuint& nTexture) + { + glGenTextures(1, &nTexture); + CHECK_GL_ERROR(); + } + + void active(GLuint nTextureUnit) + { + if (mnCurrentTextureUnit != nTextureUnit) + { + glActiveTexture(GL_TEXTURE0 + nTextureUnit); + CHECK_GL_ERROR(); + mnCurrentTextureUnit = nTextureUnit; + } + + } + + void bind(GLuint nTexture) + { + if (maBoundTextures[mnCurrentTextureUnit] != nTexture) + { + glBindTexture(GL_TEXTURE_2D, nTexture); + CHECK_GL_ERROR(); + maBoundTextures[mnCurrentTextureUnit] = nTexture; + } + } + + void unbindAndDelete(GLuint nTexture) + { + unbind(nTexture); + glDeleteTextures(1, &nTexture); + } + + void unbind(GLuint nTexture) + { + for (size_t i = 0; i < maBoundTextures.size(); i++) + { + if (nTexture == maBoundTextures[i]) + maBoundTextures[i] = 0; + } + } + +}; + + + +#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_STATE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/VertexUtils.hxx b/vcl/inc/opengl/VertexUtils.hxx new file mode 100644 index 000000000..910b8725a --- /dev/null +++ b/vcl/inc/opengl/VertexUtils.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_VERTEXUTILS_H +#define INCLUDED_VCL_INC_OPENGL_VERTEXUTILS_H + +#include +#include +#include +#include +#include + +namespace vcl +{ +namespace vertex +{ + +template +inline void addRectangle(std::vector& rVertices, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); + +template<> +inline void addRectangle(std::vector& rVertices, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + rVertices.insert(rVertices.end(), { + x1, y1, x2, y1, x1, y2, + x1, y2, x2, y1, x2, y2 + }); +} + +template<> +inline void addRectangle(std::vector& rVertices, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + rVertices.insert(rVertices.end(), { + x1, y2, x1, y1, + x2, y1, x2, y2 + }); +} + +inline void createColor(Color nColor, GLfloat fTransparency, GLubyte& nR, GLubyte& nG, GLubyte& nB, GLubyte& nA) +{ + nR = nColor.GetRed(); + nG = nColor.GetGreen(); + nB = nColor.GetBlue(); + nA = (1.0f - fTransparency) * 255.0f; +} + +template +inline void addQuadColors(std::vector& rColors, Color nColor, GLfloat fTransparency); + +template<> +inline void addQuadColors(std::vector& rColors, Color nColor, GLfloat fTransparency) +{ + GLubyte nR, nG, nB, nA; + createColor(nColor, fTransparency, nR, nG, nB, nA); + + rColors.insert(rColors.end(), { + nR, nG, nB, nA, + nR, nG, nB, nA, + nR, nG, nB, nA, + nR, nG, nB, nA, + nR, nG, nB, nA, + nR, nG, nB, nA, + }); +} + +inline void addLineSegmentVertices(std::vector& rVertices, std::vector& rExtrusionVectors, + glm::vec2 prevPoint, glm::vec2 prevExtrusionVector, GLfloat prevLength, + glm::vec2 currPoint, glm::vec2 currExtrusionVector, GLfloat currLength) +{ + rVertices.insert(rVertices.end(), { + prevPoint.x, prevPoint.y, + prevPoint.x, prevPoint.y, + currPoint.x, currPoint.y, + currPoint.x, currPoint.y, + prevPoint.x, prevPoint.y, + currPoint.x, currPoint.y, + }); + + rExtrusionVectors.insert(rExtrusionVectors.end(), { + -prevExtrusionVector.x, -prevExtrusionVector.y, -prevLength, + prevExtrusionVector.x, prevExtrusionVector.y, prevLength, + -currExtrusionVector.x, -currExtrusionVector.y, -currLength, + -currExtrusionVector.x, -currExtrusionVector.y, -currLength, + prevExtrusionVector.x, prevExtrusionVector.y, prevLength, + currExtrusionVector.x, currExtrusionVector.y, currLength, + }); +} + +inline glm::vec2 normalize(const glm::vec2& vector) +{ + if (glm::length(vector) > 0.0) + return glm::normalize(vector); + return vector; +} + +inline glm::vec2 perpendicular(const glm::vec2& vector) +{ + return glm::vec2(-vector.y, vector.x); +} + +inline float lineVectorAngle(const glm::vec2& previous, const glm::vec2& next) +{ + float angle = std::atan2(previous.x * next.y - previous.y * next.x, + previous.x * next.x + previous.y * next.y); + + return F_PI - std::fabs(angle); +} + +}} // end vcl::vertex + +#endif // INCLUDED_VCL_INC_OPENGL_VERTEXUTILS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/framebuffer.hxx b/vcl/inc/opengl/framebuffer.hxx new file mode 100644 index 000000000..4445e6198 --- /dev/null +++ b/vcl/inc/opengl/framebuffer.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_FRAMEBUFFER_H +#define INCLUDED_VCL_INC_OPENGL_FRAMEBUFFER_H + +#include + +#include + +class OpenGLFramebuffer final +{ +private: + GLuint mnId; + int mnWidth; + int mnHeight; + GLuint mnAttachedTexture; + +public: + OpenGLFramebuffer(); + ~OpenGLFramebuffer(); + + int GetWidth() const { return mnWidth; }; + int GetHeight() const { return mnHeight; }; + + void Bind(GLenum eTarget = GL_FRAMEBUFFER); + + static void Unbind(GLenum eTarget = GL_FRAMEBUFFER); + + VCL_DLLPUBLIC bool IsFree() const; + bool IsAttached( GLuint nTexture ) const; + bool IsAttached( const OpenGLTexture& rTexture ) const; + void AttachTexture( const OpenGLTexture& rTexture ); + void DetachTexture(); + +public: + OpenGLFramebuffer* mpPrevFramebuffer; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_FRAMEBUFFER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/gdiimpl.hxx b/vcl/inc/opengl/gdiimpl.hxx new file mode 100644 index 000000000..a6de106a6 --- /dev/null +++ b/vcl/inc/opengl/gdiimpl.hxx @@ -0,0 +1,395 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OPENGLGDIIMPL_HXX +#define INCLUDED_VCL_OPENGLGDIIMPL_HXX + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +class SalFrame; +class SalVirtualDevice; +class OpenGLTests; + +namespace basegfx +{ +class B2DTrapezoid; +}; + +namespace tools +{ + class Polygon; + class PolyPolygon; +} + +struct TextureCombo +{ + std::unique_ptr mpTexture; + std::unique_ptr mpMask; +}; + +class OpenGLFlushIdle; + +class VCL_DLLPUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl +{ + friend class OpenGLTests; +protected: + + /// This context is solely for blitting maOffscreenTex + rtl::Reference mpWindowContext; + + /// This context is whatever is most convenient to render + /// to maOffscreenTex with. + rtl::Reference mpContext; + + SalGraphics& mrParent; + /// Pointer to the SalFrame or SalVirtualDevice + SalGeometryProvider* mpProvider; + OpenGLProgram* mpProgram; + + /// This idle handler is used to swap buffers after rendering. + std::unique_ptr mpFlush; + + // clipping + vcl::Region maClipRegion; + bool mbUseScissor; + bool mbUseStencil; + + bool mbXORMode; + + bool mbAcquiringOpenGLContext; + + /** + * All rendering happens to this off-screen texture. For + * non-virtual devices, ie. windows - we will blit it and + * swapBuffers later. + */ + OpenGLTexture maOffscreenTex; + + Color mnLineColor; + Color mnFillColor; +#ifdef DBG_UTIL + bool mProgramIsSolidColor; +#endif + sal_uInt32 mnDrawCount; + sal_uInt32 mnDrawCountAtFlush; + Color mProgramSolidColor; + double mProgramSolidTransparency; + + std::unique_ptr mpRenderList; + + void ImplInitClipRegion(); + void ImplSetClipBit( const vcl::Region& rClip, GLuint nMask ); + void ImplDrawLineAA( double nX1, double nY1, double nX2, double nY2, bool edge ); + void CheckOffscreenTexture(); + + void ApplyProgramMatrices(float fPixelOffset = 0.0); + +public: + bool UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble = "" ); + bool UseSolid( Color nColor, sal_uInt8 nTransparency ); + bool UseSolid( Color nColor, double fTransparency ); + bool UseSolid( Color nColor ); + void UseSolid(); + bool UseLine(Color nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA); + void UseLine(GLfloat fLineWidth, bool bUseAA); + bool UseInvert50(); + bool UseInvert(SalInvert nFlags); + + void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA = false ); + void DrawConvexPolygon( const tools::Polygon& rPolygon, bool blockAA ); + void DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA ); + void DrawRect( long nX, long nY, long nWidth, long nHeight ); + void DrawRect( const tools::Rectangle& rRect ); + void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); + void DrawLineSegment(float x1, float y1, float x2, float y2); + void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA = false ); + void DrawRegionBand( const RegionBand& rRegion ); + void DrawTextureRect( const SalTwoRect& rPosAry ); + void DrawTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted = false ); + void DrawTransformedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY ); + void DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool pPremultiplied ); + void DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted ); + void DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry ); + void DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry ); + void DrawMask( OpenGLTexture& rTexture, Color nMaskColor, const SalTwoRect& rPosAry ); + void DrawLinearGradient( const Gradient& rGradient, const tools::Rectangle& rRect ); + void DrawAxialGradient( const Gradient& rGradient, const tools::Rectangle& rRect ); + void DrawRadialGradient( const Gradient& rGradient, const tools::Rectangle& rRect ); + + void FlushDeferredDrawing(); + void FlushLinesOrTriangles(DrawShaderType eType, RenderParameters const & rParameters); + +public: + // get the width of the device + GLfloat GetWidth() const { return mpProvider ? mpProvider->GetWidth() : 1; } + + // get the height of the device + GLfloat GetHeight() const { return mpProvider ? mpProvider->GetHeight() : 1; } + + /** + * check whether this instance is used for offscreen (Virtual Device) + * rendering ie. does it need its own context. + */ + bool IsOffscreen() const { return mpProvider == nullptr || mpProvider->IsOffScreen(); } + + /// Oddly not all operations obey the XOR option. + enum XOROption { IGNORE_XOR, IMPLEMENT_XOR }; + + // initialize pre-draw state + void InitializePreDrawState(XOROption eOpt); + + // operations to do before painting + void PreDraw(XOROption eOpt = IGNORE_XOR); + + // operations to do after painting + void PostDraw(); + + void PostBatchDraw(); + +protected: + bool AcquireContext(bool bForceCreate = false); + void ReleaseContext(); + + /// create a new context for rendering to the underlying window + virtual rtl::Reference CreateWinContext() = 0; + + /// check whether the given context can be used for off-screen rendering + static bool UseContext( const rtl::Reference &pContext ) + { + return pContext->isInitialized() && // not released by the OS etc. + pContext->isVCLOnly(); + } + +public: + OpenGLSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider *pProvider); + virtual ~OpenGLSalGraphicsImpl () override; + + rtl::Reference GetOpenGLContext(); + + virtual void Init() override; + + virtual void DeInit() override; + + virtual void freeResources() override; + + virtual OUString getRenderBackendName() const override { return "opengl"; } + + const vcl::Region& getClipRegion() const; + virtual bool setClipRegion( const vcl::Region& ) override; + + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const override; + + // get the width of the device + virtual long GetGraphicsWidth() const override; + + // set the clip region to empty + virtual void ResetClipRegion() override; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() override; + + // set the line color to a specific color + virtual void SetLineColor( Color nColor ) override; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() override; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( Color nColor ) override; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) override; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) override; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + bool bWindowInvalidate ) override; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + void DoCopyBits(const SalTwoRect& rPosAry, OpenGLSalGraphicsImpl &rSrcImpl); + + virtual bool blendBitmap( + const SalTwoRect&, + const SalBitmap& rBitmap ) override; + + virtual bool blendAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) override; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) override; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + + virtual Color getPixel( long nX, long nY ) override; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) override; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) override; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uInt32 nSize ) override; + + /** 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 ) override; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + + /** Render solid rectangle with given transparency + + @param nX Top left coordinate of rectangle + + @param nY Bottom right coordinate of rectangle + + @param nWidth Width of rectangle + + @param nHeight Height of rectangle + + @param nTransparency Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + + @returns true if successfully drawn, false if not able to draw rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) override; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) override; + + virtual bool supportsOperation(OutDevSupportType eType) const override; + + /// queue an idle flush of contents of the back-buffer to the screen + void flush(); + +public: + /// do flush of contents of the back-buffer to the screen & swap. + void doFlush(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/program.hxx b/vcl/inc/opengl/program.hxx new file mode 100644 index 000000000..bff248d9b --- /dev/null +++ b/vcl/inc/opengl/program.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_PROGRAM_H +#define INCLUDED_VCL_INC_OPENGL_PROGRAM_H + +#include + +#include + +#include + +#include +#include +#include + +#include + +class Color; + +enum class TextureShaderType +{ + Normal = 0, + Blend, + Masked, + Diff, + MaskedColor +}; + +enum class DrawShaderType +{ + Normal = 0, + Line +}; + +class OpenGLProgram +{ +private: + GLuint mnId; + std::unordered_map< OString, GLuint > + maUniformLocations; + sal_uInt32 mnEnabledAttribs; + GLuint mnPositionAttrib; + GLuint mnTexCoordAttrib; + GLuint mnAlphaCoordAttrib; + GLuint mnMaskCoordAttrib; + GLuint mnExtrusionVectorsAttrib; + GLuint mnVertexColorsAttrib; + + std::vector< OpenGLTexture > maTextures; + bool mbBlending; + + float mfLastWidth; + float mfLastHeight; + float mfLastPixelOffset; + + + OpenGLProgram(const OpenGLProgram &) = delete; +public: + OpenGLProgram(); + ~OpenGLProgram(); + + GLuint Id() { return mnId; } + + bool Load( const OUString& rVertexShader, const OUString& rFragmentShader, + const OString& preamble, const OString& rDigest ); + void Use(); + void Reuse(); + void Clean(); + + void SetVertices( const GLvoid* pData ); + void SetTextureCoord( const GLvoid* pData ); + void SetAlphaCoord( const GLvoid* pData ); + void SetMaskCoord(const GLvoid* pData); + void SetExtrusionVectors(const GLvoid* pData); + void SetVertexColors(std::vector& rColorVector); + + void SetUniform1f( const OString& rName, GLfloat v1 ); + void SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 ); + void SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat const * aValues ); + void SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat const * aValues ); + void SetUniform1i( const OString& rName, GLint v1 ); + void SetColor( const OString& rName, const Color& rColor ); + void SetColor( const OString& rName, Color nColor, sal_uInt8 nTransparency ); + void SetColorf( const OString& rName, Color nColor, double fTransparency ); + void SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor ); + void SetTexture( const OString& rName, OpenGLTexture& rTexture ); + void SetTransform( const OString& rName, const OpenGLTexture& rTexture, + const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY ); + void SetIdentityTransform(const OString& rName); + void SetShaderType(TextureShaderType eTextureShaderType); + void SetShaderType(DrawShaderType eDrawShaderType); + + void SetBlendMode( GLenum nSFactor, GLenum nDFactor ); + + void ApplyMatrix(float fWidth, float fHeight, float fPixelOffset = 0.0f); + + void DrawTexture( const OpenGLTexture& rTexture ); + + void DrawArrays(GLenum aMode, std::vector& aVertices); + void DrawElements(GLenum aMode, GLuint nNumberOfVertices); + + bool EnableVertexAttrib(GLuint& rAttrib, const OString& rName); + + void SetVertexAttrib(GLuint& rAttrib, const OString& rName, GLint nSize, + GLenum eType, GLboolean bNormalized, GLsizei aStride, + const GLvoid* pPointer); + +private: + GLuint GetUniformLocation( const OString& rName ); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_PROGRAM_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/salbmp.hxx b/vcl/inc/opengl/salbmp.hxx new file mode 100644 index 000000000..a01eca89f --- /dev/null +++ b/vcl/inc/opengl/salbmp.hxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_SALBMP_H +#define INCLUDED_VCL_INC_OPENGL_SALBMP_H + +#include + +#include + +#include + +#include + +struct BitmapBuffer; +class BitmapPalette; +namespace vcl +{ + class Kernel; +} + +class VCL_PLUGIN_PUBLIC OpenGLSalBitmap final : public SalBitmap +{ +private: + OpenGLTexture maTexture; + bool mbDirtyTexture; + BitmapPalette maPalette; + std::shared_ptr mpUserBuffer; + sal_uInt16 mnBits; + sal_uInt32 mnBytesPerRow; + int mnWidth; + int mnHeight; + + virtual void updateChecksum() const override; + + bool calcChecksumGL(OpenGLTexture& rInputTexture, BitmapChecksum& rChecksum) const; + +public: + OpenGLSalBitmap(); + virtual ~OpenGLSalBitmap() override; + +public: + + // SalBitmap methods + bool Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) override; + bool Create( const SalBitmap& rSalBmp ) override; + bool Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) override; + bool Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) override; + virtual bool Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false ) override; + + void Destroy() final override; + + Size GetSize() const override; + sal_uInt16 GetBitCount() const override; + + BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override; + void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override; + + bool GetSystemData( BitmapSystemData& rData ) override; + + bool ScalingSupported() const override; + bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) override; + bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) override; + bool ConvertToGreyscale() override; + bool InterpretAs8Bit() override; + +public: + + void Create( const OpenGLTexture& rTex, long nX, long nY, long nWidth, long nHeight ); + OpenGLTexture& GetTexture() const; + const BitmapPalette& GetBitmapPalette() const { return maPalette; } + +private: + + GLuint CreateTexture(); + bool AllocateUserData(); + void DeallocateUserData(); + bool ReadTexture(); + +private: + + bool ImplScaleFilter( const rtl::Reference< OpenGLContext > &xContext, const double& rScaleX, const double& rScaleY, GLenum nFilter ); + static void ImplCreateKernel( const double& fScale, const vcl::Kernel& rKernel, GLfloat*& pWeights, sal_uInt32& aKernelSize ); + bool ImplScaleConvolution(const rtl::Reference< OpenGLContext > &xContext, const double& rScaleX, const double& rScaleY, const vcl::Kernel& rKernel); + bool ImplScaleArea( const rtl::Reference< OpenGLContext > &xContext, + double rScaleX, double rScaleY ); + +public: + + void ImplScale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx new file mode 100644 index 000000000..0438b9af1 --- /dev/null +++ b/vcl/inc/opengl/texture.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_TEXTURE_H +#define INCLUDED_VCL_INC_OPENGL_TEXTURE_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +class ImplOpenGLTexture +{ +public: + GLuint mnTexture; + int mnWidth; + int mnHeight; + GLenum mnFilter; + GLuint mnOptStencil; + + std::unique_ptr> mpSlotReferences; + std::function mFunctSlotDeallocateCallback; + + ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ); + ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ); + ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ); + ~ImplOpenGLTexture(); + + bool InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData); + + void IncreaseRefCount(int nSlotNumber); + void DecreaseRefCount(int nSlotNumber); + + void InitializeSlotMechanism(int nInitialSlotSize); + + void SetSlotDeallocateCallback(std::function aCallback) + { + mFunctSlotDeallocateCallback = aCallback; + } + + void ResetSlotDeallocateCallback() + { + mFunctSlotDeallocateCallback = std::function(); + } + + GLuint AddStencil(); +}; + +class VCL_DLLPUBLIC OpenGLTexture final +{ +private: + // if the rect size doesn't match the mpImpl one, this instance + // is a sub-area from the real OpenGL texture + tools::Rectangle maRect; + std::shared_ptr mpImpl; + int mnSlotNumber; + + inline void GetTextureRect(const SalTwoRect& rPosAry, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const; + + bool IsValid() const + { + return (mpImpl && mpImpl->mnTexture != 0); + } + +public: + OpenGLTexture(); + OpenGLTexture(const std::shared_ptr& pImpl, tools::Rectangle aRectangle, int nSlotNumber); + + OpenGLTexture( int nWidth, int nHeight, bool bAllocate = true ); + OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ); + OpenGLTexture( int nX, int nY, int nWidth, int nHeight ); + OpenGLTexture( const OpenGLTexture& rTexture ); + OpenGLTexture( OpenGLTexture&& rTexture ) noexcept; + OpenGLTexture( const OpenGLTexture& rTexture, int nX, int nY, int nWidth, int nHeight ); + ~OpenGLTexture(); + + bool IsUnique() const; + + GLuint Id() const; + int GetWidth() const; + int GetHeight() const; + + void GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted=false ) const; + void GetWholeCoord( GLfloat* pCoord ) const; + void Bind(); + void Unbind(); + void Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ); + GLuint AddStencil(); + GLuint StencilId() const; + + bool CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData); + + void SaveToFile(const OUString& rFileName); + + GLenum GetFilter() const; + void SetFilter( GLenum nFilter ); + + operator bool() const; + OpenGLTexture& operator=( const OpenGLTexture& rTexture ); + OpenGLTexture& operator=( OpenGLTexture&& rTexture ); + bool operator==( const OpenGLTexture& rTexture ) const; + bool operator!=( const OpenGLTexture& rTexture ) const; + + template + void FillCoords(std::vector& aCoordVector, const SalTwoRect& rPosAry) const; +}; + +template<> void OpenGLTexture::FillCoords( + std::vector& aCoord, const SalTwoRect& rPosAry) + const; + +template<> void OpenGLTexture::FillCoords( + std::vector& aCoord, const SalTwoRect& rPosAry) + const; + +#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/win/WinDeviceInfo.hxx b/vcl/inc/opengl/win/WinDeviceInfo.hxx new file mode 100644 index 000000000..04d97406b --- /dev/null +++ b/vcl/inc/opengl/win/WinDeviceInfo.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_OPENGL_WIN_WINDEVICEINFO_HXX +#define INCLUDED_VCL_OPENGL_WIN_WINDEVICEINFO_HXX + +#include + +#include +#include + +#include +#include +#include + +class VCL_DLLPUBLIC WinOpenGLDeviceInfo : public OpenGLDeviceInfo +{ +private: + OUString maDriverVersion; + OUString maDriverVersion2; + + OUString maDriverDate; + OUString maDriverDate2; + + OUString maDeviceID; + OUString maDeviceID2; + + OUString maAdapterVendorID; + OUString maAdapterDeviceID; + OUString maAdapterSubsysID; + + OUString maAdapterVendorID2; + OUString maAdapterDeviceID2; + OUString maAdapterSubsysID2; + + OUString maDeviceKey; + OUString maDeviceKey2; + + OUString maDeviceString; + OUString maDeviceString2; + + bool mbHasDualGPU; + bool mbRDP; + + void GetData(); + bool FindBlocklistedDeviceInList(); + +public: + WinOpenGLDeviceInfo(); + + virtual ~WinOpenGLDeviceInfo() override; + + virtual bool isDeviceBlocked() override; + + const OUString& GetDriverVersion() const + { + return maDriverVersion; + } + + const OUString& GetDriverDate() const + { + return maDriverDate; + } + + const OUString& GetDeviceID() const + { + return maDeviceID; + } + + const OUString& GetAdapterVendorID() const + { + return maAdapterVendorID; + } + + const OUString& GetAdapterDeviceID() const + { + return maAdapterDeviceID; + } + + const OUString& GetAdapterSubsysID() const + { + return maAdapterSubsysID; + } + const OUString& GetDeviceKey() const + { + return maDeviceKey; + } + + const OUString& GetDeviceString() const + { + return maDeviceString; + } +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx new file mode 100644 index 000000000..dff47ef7e --- /dev/null +++ b/vcl/inc/opengl/win/gdiimpl.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_WIN_GDIIMPL_HXX +#define INCLUDED_VCL_INC_OPENGL_WIN_GDIIMPL_HXX + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +class OpenGLCompatibleDC : public CompatibleDC +{ +public: + OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height); + + virtual std::unique_ptr getAsMaskTexture() const override; + // caller must delete + OpenGLTexture* getOpenGLTexture() const; + + /// Copy bitmap data to the texture. Texture must be initialized and the correct size to hold the bitmap. + bool copyToTexture(Texture& aTexture) const; + + struct Texture; +}; + +struct OpenGLCompatibleDC::Texture : public CompatibleDC::Texture +{ + OpenGLTexture texture; + virtual bool isValid() const { return !!texture; } + virtual int GetWidth() const { return texture.GetWidth(); } + virtual int GetHeight() const { return texture.GetHeight(); } +}; + +class WinOpenGLSalGraphicsImpl : public OpenGLSalGraphicsImpl, public WinSalGraphicsImplBase +{ + friend class WinLayout; +private: + WinSalGraphics& mrWinParent; + + bool RenderCompatibleDC(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack, + int nX, int nY, TextureCombo& rCombo); + +public: + WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics, + SalGeometryProvider *mpProvider); + +protected: + virtual rtl::Reference CreateWinContext() override; + + bool RenderTextureCombo(TextureCombo const & rCombo, int nX, int nY); + +public: + virtual void Init() override; + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) override; + + virtual bool UseTextDraw() const override { return true; } + virtual void PreDrawText() override; + virtual void PostDrawText() override; + virtual void DrawTextMask( CompatibleDC::Texture* rTexture, Color nMaskColor, const SalTwoRect& rPosAry ) override; + using OpenGLSalGraphicsImpl::DrawMask; + virtual void DeferredTextDraw(const CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry) override; + + virtual bool UseRenderNativeControl() const override { return true; } + virtual bool TryRenderCachedNativeControl(ControlCacheKey const & rControlCacheKey, int nX, int nY) override; + virtual bool RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, + int nX, int nY , ControlCacheKey& aControlCacheKey) override; + +}; + +typedef std::pair> OpenGLControlCachePair; +typedef o3tl::lru_map, ControlCacheHashFunction> OpenGLControlCacheType; + +class OpenGLControlsCache { + OpenGLControlCacheType cache; + + OpenGLControlsCache(); + +public: + static OpenGLControlCacheType & get(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/win/winlayout.hxx b/vcl/inc/opengl/win/winlayout.hxx new file mode 100644 index 000000000..d017bc250 --- /dev/null +++ b/vcl/inc/opengl/win/winlayout.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_WIN_WINLAYOUT_HXX +#define INCLUDED_VCL_INC_OPENGL_WIN_WINLAYOUT_HXX + +#include +#include + +struct OpenGLGlobalWinGlyphCache : public GlobalWinGlyphCache +{ + OpenGLGlobalWinGlyphCache() + : maPackedTextureAtlas(2048, 2048) + { + } + + PackedTextureAtlasManager maPackedTextureAtlas; + + virtual bool AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) override; + virtual void Prune() override; +}; + +class OpenGLWinGlyphCache : public WinGlyphCache +{ +public: + void RemoveTextures(std::vector& rTextureIDs); + +private: + // This class just "adds" RemoveTextures() to the base class, it's never instantiated. + OpenGLWinGlyphCache() = delete; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_WIN_WINLAYOUT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/X11DeviceInfo.hxx b/vcl/inc/opengl/x11/X11DeviceInfo.hxx new file mode 100644 index 000000000..d51de3a69 --- /dev/null +++ b/vcl/inc/opengl/x11/X11DeviceInfo.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_X11_X11DEVICEINFO_HXX +#define INCLUDED_VCL_INC_OPENGL_X11_X11DEVICEINFO_HXX + +#include + +#include + +class X11OpenGLDeviceInfo final : public OpenGLDeviceInfo +{ +private: + bool mbIsMesa; + bool mbIsNVIDIA; + bool mbIsFGLRX; + bool mbIsNouveau; + bool mbIsIntel; + bool mbIsOldSwrast; + bool mbIsLlvmpipe; + + OString maVendor; + OString maRenderer; + OString maVersion; + OString maOS; + OString maOSRelease; + + size_t mnGLMajorVersion; + size_t mnMajorVersion; + size_t mnMinorVersion; + size_t mnRevisionVersion; + + void GetData(); + +public: + X11OpenGLDeviceInfo(); + + virtual bool isDeviceBlocked() override; + + const OString& GetVendor() const + { + return maVendor; + } + + const OString& GetRenderer() const + { + return maRenderer; + } + + const OString& GetVersion() const + { + return maVersion; + } + + const OString& GetOS() const + { + return maOS; + } + + const OString& GetOSRelease() const + { + return maOSRelease; + } + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/cairotextrender.hxx b/vcl/inc/opengl/x11/cairotextrender.hxx new file mode 100644 index 000000000..137022fa8 --- /dev/null +++ b/vcl/inc/opengl/x11/cairotextrender.hxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_GENERIC_GDI_OPENGLX11CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_UNX_GENERIC_GDI_OPENGLX11CAIROTEXTRENDER_HXX + +#include + +class OpenGLX11CairoTextRender final : public X11CairoTextRender +{ +public: + explicit OpenGLX11CairoTextRender(X11SalGraphics& rParent); + + virtual cairo_t* getCairoContext() override; + virtual void getSurfaceOffset(double& nDX, double& nDY) override; + virtual void releaseCairoContext(cairo_t* cr) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/gdiimpl.hxx b/vcl/inc/opengl/x11/gdiimpl.hxx new file mode 100644 index 000000000..d86af9223 --- /dev/null +++ b/vcl/inc/opengl/x11/gdiimpl.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX +#define INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX + +#include + +#include +#include +#include +#include + +struct TextureCombo; + +class X11OpenGLSalGraphicsImpl : public OpenGLSalGraphicsImpl, public X11GraphicsImpl +{ +private: + X11SalGraphics& mrX11Parent; + +public: + X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ); + virtual ~X11OpenGLSalGraphicsImpl() override; + +protected: + virtual rtl::Reference CreateWinContext() override; + +public: + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) override; + + virtual void Init() override; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/glxtest.hxx b/vcl/inc/opengl/x11/glxtest.hxx new file mode 100644 index 000000000..5715a6d9f --- /dev/null +++ b/vcl/inc/opengl/x11/glxtest.hxx @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_X11_GLXTEST_HXX +#define INCLUDED_VCL_INC_OPENGL_X11_GLXTEST_HXX + +#include + +VCL_DLLPUBLIC int* getGlxPipe(); + +VCL_DLLPUBLIC pid_t* getGlxPid(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/salvd.hxx b/vcl/inc/opengl/x11/salvd.hxx new file mode 100644 index 000000000..a77b9874e --- /dev/null +++ b/vcl/inc/opengl/x11/salvd.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_X11_SALVD_H +#define INCLUDED_VCL_INC_OPENGL_X11_SALVD_H + +#include +#include +#include + +#include +#include + +class SalDisplay; +class X11OpenGLSalGraphics; +class X11SalGraphics; + +class X11OpenGLSalVirtualDevice : public SalVirtualDevice +{ + SalDisplay *mpDisplay; + std::unique_ptr + mpGraphics; + bool mbGraphics; // is Graphics used + SalX11Screen mnXScreen; + int mnWidth; + int mnHeight; + +public: + X11OpenGLSalVirtualDevice( SalGraphics const *pGraphics, + long nDX, long nDY, + const SystemGraphicsData *pData, + std::unique_ptr pNewGraphics); + virtual ~X11OpenGLSalVirtualDevice() override; + + // SalGeometryProvider + virtual long GetWidth() const override { return mnWidth; } + virtual long GetHeight() const override { return mnHeight; } + + SalDisplay * GetDisplay() const { return mpDisplay; } + const SalX11Screen& GetXScreenNumber() const { return mnXScreen; } + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + // Set new size, without saving the old contents + virtual bool SetSize( long nNewDX, long nNewDY ) override; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_X11_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/zone.hxx b/vcl/inc/opengl/zone.hxx new file mode 100644 index 000000000..4bcdf15dc --- /dev/null +++ b/vcl/inc/opengl/zone.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_ZONE_H +#define INCLUDED_VCL_INC_OPENGL_ZONE_H + +#include +#include +#include +#include + +/** + * We want to be able to detect if a given crash came + * from the OpenGL code, so use this helper to track that. + */ +class VCL_DLLPUBLIC OpenGLZone : public CrashZone< OpenGLZone > { +public: + static void hardDisable(); + static void relaxWatchdogTimings(); + static const CrashWatchdogTimingsValues& getCrashWatchdogTimingsValues(); + static void checkDebug( int nUnchanged, const CrashWatchdogTimingsValues& aTimingValues ); + static const char* name() { return "OpenGL"; } +}; + +/// Create this to not only enter the zone, but set VCL context. +class OpenGLVCLContextZone { + OpenGLZone aZone; +public: + OpenGLVCLContextZone(); +}; + +class VCL_DLLPUBLIC PreDefaultWinNoOpenGLZone { +public: + PreDefaultWinNoOpenGLZone(); + ~PreDefaultWinNoOpenGLZone(); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_ZONE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/a11yfactory.h b/vcl/inc/osx/a11yfactory.h new file mode 100644 index 000000000..b20755a03 --- /dev/null +++ b/vcl/inc/osx/a11yfactory.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_A11YFACTORY_H +#define INCLUDED_VCL_INC_OSX_A11YFACTORY_H + +#include "osxvcltypes.h" +#include "a11ywrapper.h" +#include + +@interface AquaA11yFactory : NSObject +{ +} ++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; ++(AquaA11yWrapper *)wrapperForAccessible: (css::uno::Reference < css::accessibility::XAccessible >) rxAccessible; ++(AquaA11yWrapper *)wrapperForAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; ++(AquaA11yWrapper *)wrapperForAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(BOOL) bCreate; ++(AquaA11yWrapper *)wrapperForAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext createIfNotExists:(BOOL) bCreate asRadioGroup:(BOOL) asRadioGroup; ++(void)removeFromWrapperRepositoryFor: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; ++(void)registerView: (NSView *) theView; ++(void)revokeView: (NSView *) theViewt; +@end + +#endif // INCLUDED_VCL_INC_OSX_A11YFACTORY_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/a11yfocustracker.hxx b/vcl/inc/osx/a11yfocustracker.hxx new file mode 100644 index 000000000..59f2e579c --- /dev/null +++ b/vcl/inc/osx/a11yfocustracker.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_A11YFOCUSTRACKER_HXX +#define INCLUDED_VCL_INC_OSX_A11YFOCUSTRACKER_HXX + +#include + +#include "keyboardfocuslistener.hxx" + +#include + +#include +#include +#include + +namespace vcl { class Window; } +class ToolBox; +class DocumentFocusListener; + + +class AquaA11yFocusTracker +{ + +public: + AquaA11yFocusTracker(); + + ~AquaA11yFocusTracker(); + + css::uno::Reference< css::accessibility::XAccessible > const & getFocusedObject() { return m_xFocusedObject; }; + + // sets the currently focus object and notifies the FocusEventListener (if any) + void setFocusedObject(const css::uno::Reference< css::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 + void window_got_focus(vcl::Window *pWindow); + + // received a TOOLBOX_HIGHLIGHT event for this window + void toolbox_highlight_on(vcl::Window *pWindow); + + // received a TOOLBOX_HIGHLIGHTOFF event for this window + void toolbox_highlight_off(vcl::Window const *pWindow); + + // received a TABPAGE_ACTIVATE event for this window + void tabpage_activated(vcl::Window *pWindow); + + // received a MENU_HIGHLIGHT event for this window + void menu_highlighted(const ::VclMenuEvent *pEvent); + + // toolbox items are widgets in gtk+ and Cocoa + void notify_toolbox_item_focus(ToolBox *pToolBox); + + // toolbox item opened a floating window (e.g. color chooser) + void toolbox_open_floater(vcl::Window *pWindow); + + // callback function for Application::addEventListener + static void WindowEventHandler(void * pThis, VclSimpleEvent&); + +private: + // the accessible object that has the keyboard focus (if any) + css::uno::Reference< css::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> m_aDocumentWindowList; + + // the link object needed for Application::addEventListener + Link m_aWindowEventLink; + + // the UNO XAccessibilityEventListener for Documents and other non VCL objects + const rtl::Reference< DocumentFocusListener > m_xDocumentFocusListener; +}; + +struct TheAquaA11yFocusTracker: + rtl::Static +{}; + +#endif // INCLUDED_VCL_INC_OSX_A11YFOCUSTRACKER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/a11ylistener.hxx b/vcl/inc/osx/a11ylistener.hxx new file mode 100644 index 000000000..a53559467 --- /dev/null +++ b/vcl/inc/osx/a11ylistener.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_A11YLISTENER_HXX +#define INCLUDED_VCL_INC_OSX_A11YLISTENER_HXX + +#include +#include + +#include "a11yfocustracker.hxx" +#include "osxvcltypes.h" +#include +#include + + +class AquaA11yEventListener : + public ::cppu::WeakImplHelper< css::accessibility::XAccessibleEventListener > +{ + +public: + AquaA11yEventListener(id wrapperObject, sal_Int16 role); + virtual ~AquaA11yEventListener() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XAccessibleEventListener + virtual void SAL_CALL notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) override; + +private: + const id m_wrapperObject; + const sal_Int16 m_role; + css::awt::Rectangle m_oldBounds; +}; + +#endif // INCLUDED_VCL_INC_OSX_A11YLISTENER_HXX +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/a11ywrapper.h b/vcl/inc/osx/a11ywrapper.h new file mode 100644 index 000000000..e33d247a1 --- /dev/null +++ b/vcl/inc/osx/a11ywrapper.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_A11YWRAPPER_H +#define INCLUDED_VCL_INC_OSX_A11YWRAPPER_H + +#include "osxvcltypes.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// rAccessibleXYZ as a field in an Objective-C-Class would not call Con-/Destructor, so use a struct instead +struct ReferenceWrapper +{ + css::uno::Reference < css::accessibility::XAccessibleAction > rAccessibleAction; + css::uno::Reference < css::accessibility::XAccessibleContext > rAccessibleContext; + css::uno::Reference < css::accessibility::XAccessibleComponent > rAccessibleComponent; + css::uno::Reference < css::accessibility::XAccessibleExtendedComponent > rAccessibleExtendedComponent; + css::uno::Reference < css::accessibility::XAccessibleSelection > rAccessibleSelection; + css::uno::Reference < css::accessibility::XAccessibleTable > rAccessibleTable; + css::uno::Reference < css::accessibility::XAccessibleText > rAccessibleText; + css::uno::Reference < css::accessibility::XAccessibleEditableText > rAccessibleEditableText; + css::uno::Reference < css::accessibility::XAccessibleValue > rAccessibleValue; + css::uno::Reference < css::accessibility::XAccessibleTextAttributes > rAccessibleTextAttributes; + css::uno::Reference < css::accessibility::XAccessibleMultiLineText > rAccessibleMultiLineText; + css::uno::Reference < css::accessibility::XAccessibleTextMarkup > rAccessibleTextMarkup; +}; + +@interface AquaA11yWrapper : NSView +{ + ReferenceWrapper * mpReferenceWrapper; + BOOL mActsAsRadioGroup; + BOOL mIsTableCell; +} +// NSAccessibility Protocol +-(id)accessibilityAttributeValue:(NSString *)attribute; +-(BOOL)accessibilityIsIgnored; +-(NSArray *)accessibilityAttributeNames; +-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute; +-(NSArray *)accessibilityParameterizedAttributeNames; +-(BOOL)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:(BOOL)actsAsRadioGroup; +-(BOOL)actsAsRadioGroup; +-(NSWindow*)windowForParent; +-(id)initWithAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) anAccessibleContext; +-(void) setDefaults: (css::uno::Reference < css::accessibility::XAccessibleContext >) rxAccessibleContext; +-(void) dealloc; ++(void)setPopupMenuOpen:(BOOL)popupMenuOpen; +-(css::accessibility::XAccessibleAction *)accessibleAction; +-(css::accessibility::XAccessibleContext *)accessibleContext; +-(css::accessibility::XAccessibleComponent *)accessibleComponent; +-(css::accessibility::XAccessibleExtendedComponent *)accessibleExtendedComponent; +-(css::accessibility::XAccessibleSelection *)accessibleSelection; +-(css::accessibility::XAccessibleTable *)accessibleTable; +-(css::accessibility::XAccessibleText *)accessibleText; +-(css::accessibility::XAccessibleEditableText *)accessibleEditableText; +-(css::accessibility::XAccessibleValue *)accessibleValue; +-(css::accessibility::XAccessibleTextAttributes *)accessibleTextAttributes; +-(css::accessibility::XAccessibleMultiLineText *)accessibleMultiLineText; +-(css::accessibility::XAccessibleTextMarkup *)accessibleTextMarkup; +@end + +#endif // INCLUDED_VCL_INC_OSX_A11YWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/keyboardfocuslistener.hxx b/vcl/inc/osx/keyboardfocuslistener.hxx new file mode 100644 index 000000000..1da1c8452 --- /dev/null +++ b/vcl/inc/osx/keyboardfocuslistener.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_KEYBOARDFOCUSLISTENER_HXX +#define INCLUDED_VCL_INC_OSX_KEYBOARDFOCUSLISTENER_HXX + +#include + +#include +#include + + +class KeyboardFocusListener : public salhelper::SimpleReferenceObject +{ +public: + virtual void focusedObjectChanged(const css::uno::Reference< css::accessibility::XAccessible >& xAccessible) = 0; +}; + +#endif // INCLUDED_VCL_INC_OSX_KEYBOARDFOCUSLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/osxvcltypes.h b/vcl/inc/osx/osxvcltypes.h new file mode 100644 index 000000000..bf3f4ec46 --- /dev/null +++ b/vcl/inc/osx/osxvcltypes.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_OSXVCLTYPES_H +#define INCLUDED_VCL_INC_OSX_OSXVCLTYPES_H + +#include +#import +#import +#include + +#endif // INCLUDED_VCL_INC_OSX_OSXVCLTYPES_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/printview.h b/vcl/inc/osx/printview.h new file mode 100644 index 000000000..a2a6e5454 --- /dev/null +++ b/vcl/inc/osx/printview.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_PRINTVIEW_H +#define INCLUDED_VCL_INC_OSX_PRINTVIEW_H + +#include +#include +#include + +#include + +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; +-(BOOL)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 // INCLUDED_VCL_INC_OSX_PRINTVIEW_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/runinmain.hxx b/vcl/inc/osx/runinmain.hxx new file mode 100644 index 000000000..e68bc4d35 --- /dev/null +++ b/vcl/inc/osx/runinmain.hxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX +#define INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/** + * Runs a command in the main thread. + * + * These macros are always used like a recursive calls, so they work like + * a closure. + * + * Uses two conditionals for a two way communication. + * The data (code block + result) is protected by the SolarMutex. + * + * There are three main macros, which act as function initializers: + * - OSX_RUNINMAIN - for all functions without return values + * - OSX_RUNINMAIN_POINTER - for all functions returning a pointer + * - OSX_RUNINMAIN_UNION - for all other return types + * + * All types used via OSX_RUNINMAIN_UNION must implement a move constructor, + * so there is no memory leak! + */ + +#include + +#include + +#include + +#include "saltimer.h" +#include +#include + +union RuninmainResult +{ + void* pointer; + bool boolean; + struct SalFrame::SalPointerState state; + + RuninmainResult() {} +}; + +#define OSX_RUNINMAIN_MEMBERS \ + std::mutex m_runInMainMutex; \ + std::condition_variable m_aInMainCondition; \ + std::condition_variable m_aResultCondition; \ + bool m_wakeUpMain = false; \ + bool m_resultReady = false; \ + RuninmainBlock m_aCodeBlock; \ + RuninmainResult m_aResult; + +#define OSX_RUNINMAIN( instance, command ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast(instance->GetYieldMutex()); \ + { \ + std::scoped_lock g(aMutex->m_runInMainMutex); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + command; \ + }); \ + aMutex->m_wakeUpMain = true; \ + aMutex->m_aInMainCondition.notify_all(); \ + } \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + { \ + std::unique_lock g(aMutex->m_runInMainMutex); \ + aMutex->m_aResultCondition.wait( \ + g, [&aMutex]() { return aMutex->m_resultReady; }); \ + aMutex->m_resultReady = false; \ + } \ + return; \ + } + +#define OSX_RUNINMAIN_POINTER( instance, command, type ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast(instance->GetYieldMutex()); \ + { \ + std::scoped_lock g(aMutex->m_runInMainMutex); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + aMutex->m_aResult.pointer = static_cast( command ); \ + }); \ + aMutex->m_wakeUpMain = true; \ + aMutex->m_aInMainCondition.notify_all(); \ + } \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + { \ + std::unique_lock g(aMutex->m_runInMainMutex); \ + aMutex->m_aResultCondition.wait( \ + g, [&aMutex]() { return aMutex->m_resultReady; }); \ + aMutex->m_resultReady = false; \ + } \ + return static_cast( aMutex->m_aResult.pointer ); \ + } + +#define OSX_RUNINMAIN_UNION( instance, command, member ) \ + if ( !instance->IsMainThread() ) \ + { \ + DBG_TESTSOLARMUTEX(); \ + SalYieldMutex *aMutex = static_cast(instance->GetYieldMutex()); \ + { \ + std::scoped_lock g(aMutex->m_runInMainMutex); \ + assert( !aMutex->m_aCodeBlock ); \ + aMutex->m_aCodeBlock = Block_copy(^{ \ + aMutex->m_aResult.member = command; \ + }); \ + aMutex->m_wakeUpMain = true; \ + aMutex->m_aInMainCondition.notify_all(); \ + } \ + dispatch_async(dispatch_get_main_queue(),^{ \ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); \ + }); \ + { \ + std::unique_lock g(aMutex->m_runInMainMutex); \ + aMutex->m_aResultCondition.wait( \ + g, [&aMutex]() { return aMutex->m_resultReady; }); \ + aMutex->m_resultReady = false; \ + } \ + return std::move( aMutex->m_aResult.member ); \ + } + +/** + * convenience macros used from SalInstance + */ + +#define OSX_INST_RUNINMAIN( command ) \ + OSX_RUNINMAIN( this, command ) + +#define OSX_INST_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( this, command, type ) + +#define OSX_INST_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( this, command, member ) + +/** + * convenience macros using global SalData + */ + +#define OSX_SALDATA_RUNINMAIN( command ) \ + OSX_RUNINMAIN( GetSalData()->mpInstance, command ) + +#define OSX_SALDATA_RUNINMAIN_POINTER( command, type ) \ + OSX_RUNINMAIN_POINTER( GetSalData()->mpInstance, command, type ) + +#define OSX_SALDATA_RUNINMAIN_UNION( command, member ) \ + OSX_RUNINMAIN_UNION( GetSalData()->mpInstance, command, member ) + +#endif // INCLUDED_VCL_INC_OSX_RUNINMAIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/saldata.hxx b/vcl/inc/osx/saldata.hxx new file mode 100644 index 000000000..483902ff2 --- /dev/null +++ b/vcl/inc/osx/saldata.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALDATA_HXX +#define INCLUDED_VCL_INC_OSX_SALDATA_HXX + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +class AquaSalFrame; +class AquaSalInstance; +class SalObject; +class SalFrame; +class SalVirtualDevice; +class SalPrinter; +class SystemFontList; + +#define SAL_CLIPRECT_COUNT 16 +#define INVALID_CURSOR_PTR reinterpret_cast(0xdeadbeef) + +// Singleton, instantiated from Application::Application() in +// vcl/source/app/svapp.cxx. + +class SalData +{ +public: + SALTIMERPROC mpTimerProc; // timer callback proc + AquaSalInstance *mpInstance; + std::list maPresentationFrames; // list of frames in presentation mode + 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 statuses + // at the moment this is only one add menu button + CGColorSpaceRef mxRGBSpace; + CGColorSpaceRef mxGraySpace; + + o3tl::enumarray< PointerStyle, NSCursor* > maCursors; + std::vector< NSMenuItem* > maFallbackMenu; + std::map< NSEvent*, bool > maKeyEventAnswer; + + static oslThreadKey s_aAutoReleaseKey; + + bool mbIsScrollbarDoubleMax; // TODO: support DoubleMin and DoubleBoth too +#if !HAVE_FEATURE_MACOSX_SANDBOX + AppleRemoteMainController* mpAppleRemoteMainController; +#endif + NSObject* mpDockIconClickHandler; + long mnDPIX; // #i100617# read DPI only once per office life + long mnDPIY; // #i100617# read DPI only once per office life + + css::uno::Reference< css::uno::XInterface > mxClipboard; + + SalData(); + ~SalData(); + + NSCursor* getCursor( PointerStyle i_eStyle ); + + static void ensureThreadAutoreleasePool(); + + static NSStatusItem* getStatusItem(); +}; + +inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = pData; } +inline SalData *GetSalData() { return ImplGetSVData()->mpSalData; } + +bool ImplSalYieldMutexTryToAcquire(); +void ImplSalYieldMutexRelease(); + +#endif // INCLUDED_VCL_INC_OSX_SALDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salframe.h b/vcl/inc/osx/salframe.h new file mode 100644 index 000000000..3d0f19f41 --- /dev/null +++ b/vcl/inc/osx/salframe.h @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALFRAME_H +#define INCLUDED_VCL_INC_OSX_SALFRAME_H + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +class AquaSalGraphics; +class AquaSalFrame; +class AquaSalTimer; +class AquaSalInstance; +class AquaSalMenu; + +class AquaSalFrame : public SalFrame +{ +public: + NSWindow* mpNSWindow; // Cocoa window + NSView* mpNSView; // Cocoa view (actually a custom view) + 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; // is Graphics used? + bool mbFullScreen; // is Window in FullScreen? + bool mbShown; + bool mbInitShow; + bool mbPositioned; + bool mbSized; + bool mbPresentation; + + SalFrameStyleFlags mnStyle; + unsigned int mnStyleMask; // our style mask from NSWindow creation + + sal_uInt64 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 + NSRect maTrackingRect; + + CGMutablePathRef mrClippingPath; // used for "shaping" + std::vector< CGRect > maClippingRects; + + tools::Rectangle maInvalidRect; + + InputContextFlags mnICOptions; + + // To prevent display sleep during presentation + IOPMAssertionID mnAssertionID; + + NSRect maFrameRect; + NSRect maContentRect; + + bool mbGeometryDidChange; + + int mnBlinkCursorDelay; + +public: + /** Constructor + + Creates a system window and connects this frame with it. + + @throws std::runtime_error in case window creation fails + */ + AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ); + + virtual ~AquaSalFrame() override; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool PostEvent(std::unique_ptr pData) override; + virtual void SetTitle( const OUString& rTitle ) override; + virtual void SetIcon( sal_uInt16 nIcon ) override; + virtual void SetRepresentedURL( const OUString& ) override; + virtual void SetMenu( SalMenu* pSalMenu ) override; + virtual void DrawMenuBar() override; + virtual void Show( bool bVisible, bool bNoActivate = false ) override; + virtual void SetMinClientSize( long nWidth, long nHeight ) override; + virtual void SetMaxClientSize( long nWidth, long nHeight ) override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) override; + virtual void GetClientSize( long& rWidth, long& rHeight ) override; + virtual void GetWorkArea( tools::Rectangle& rRect ) override; + virtual SalFrame* GetParent() const override; + virtual void SetWindowState( const SalFrameState* pState ) override; + virtual bool GetWindowState( SalFrameState* pState ) override; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) override; + virtual void StartPresentation( bool bStart ) override; + virtual void SetAlwaysOnTop( bool bOnTop ) override; + virtual void ToTop( SalFrameToTop nFlags ) override; + virtual void SetPointer( PointerStyle ePointerStyle ) override; + virtual void CaptureMouse( bool bMouse ) override; + virtual void SetPointerPos( long nX, long nY ) override; + virtual void Flush( void ) override; + virtual void Flush( const tools::Rectangle& ) override; + virtual void SetInputContext( SalInputContext* pContext ) override; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) override; + virtual OUString GetKeyName( sal_uInt16 nKeyCode ) override; + virtual bool MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode ) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings( AllSettings& rSettings ) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override; + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) override; + virtual void SetParent( SalFrame* pNewParent ) override; + virtual bool SetPluginParent( SystemParentData* pNewParent ) override; + virtual void SetExtendedFrameStyle( SalExtStyle ) override; + virtual void SetScreenNumber(unsigned int) override; + virtual void SetApplicationID( const OUString &rApplicationID ) override; + + // shaped system windows + // set clip region to none (-> rectangular windows, normal state) + virtual void ResetClipRegion() override; + // start setting the clipregion consisting of nRects rectangles + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + // add a rectangle to the clip region + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + // done setting up the clipregion + virtual void EndSetClipRegion() override; + + void UpdateFrameGeometry(); + + // trigger painting of the window + void SendPaintEvent( const tools::Rectangle* pRect = nullptr ); + + static inline bool isAlive( const AquaSalFrame* pFrame ); + + static AquaSalFrame* GetCaptureFrame() { return s_pCaptureFrame; } + + NSWindow* getNSWindow() const { return mpNSWindow; } + NSView* getNSView() const { return mpNSView; } + unsigned int getStyleMask() const { return mnStyleMask; } + + void getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY ); + + // actually the following 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(); + + CGMutablePathRef getClipPath() const { return mrClippingPath; } + + // called by VCL_NSApplication to indicate screen settings have changed + void screenParametersChanged(); + +protected: + SalEvent PreparePosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags); + +private: // methods + /** do things on initial show (like centering on parent or on screen) + */ + void initShow(); + + void initWindowAndView(); + + void doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ); + + void doResetClipRegion(); + +private: // data + static AquaSalFrame* s_pCaptureFrame; + + AquaSalFrame( const AquaSalFrame& ) = delete; + AquaSalFrame& operator=(const AquaSalFrame&) = delete; +}; + +inline bool AquaSalFrame::isAlive( const AquaSalFrame* pFrame ) +{ + AquaSalInstance *pInst = GetSalData()->mpInstance; + return pInst && pInst->isFrameAlive( pFrame ); +} + +#endif // INCLUDED_VCL_INC_OSX_SALFRAME_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salframeview.h b/vcl/inc/osx/salframeview.h new file mode 100644 index 000000000..36537f3db --- /dev/null +++ b/vcl/inc/osx/salframeview.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALFRAMEVIEW_H +#define INCLUDED_VCL_INC_OSX_SALFRAMEVIEW_H + +#include + +enum class SalEvent; + +@interface SalFrameWindow : NSWindow +{ + AquaSalFrame* mpFrame; + id mDraggingDestinationHandler; +} +-(id)initWithSalFrame: (AquaSalFrame*)pFrame; +-(BOOL)canBecomeKeyWindow; +-(void)displayIfNeeded; +-(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; +-(BOOL)windowShouldClose: (NSNotification*)pNotification; +//-(void)willEncodeRestorableState:(NSCoder*)pCoderState; +//-(void)didDecodeRestorableState:(NSCoder*)pCoderState; +//-(void)windowWillEnterVersionBrowser:(NSNotification*)pNotification; +-(void)dockMenuItemTriggered: (id)sender; +-(AquaSalFrame*)getSalFrame; +-(BOOL)containsMouse; +-(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext; + +/* NSDraggingDestination protocol methods + */ +-(NSDragOperation)draggingEntered:(id )sender; +-(NSDragOperation)draggingUpdated:(id )sender; +-(void)draggingExited:(id )sender; +-(BOOL)prepareForDragOperation:(id )sender; +-(BOOL)performDragOperation:(id )sender; +-(void)concludeDragOperation:(id )sender; + +-(void)registerDraggingDestinationHandler:(id)theHandler; +-(void)unregisterDraggingDestinationHandler:(id)theHandler; +@end + +@interface SalFrameView : AquaA11yWrapper +{ + AquaSalFrame* mpFrame; + + // for NSTextInput/NSTextInputClient + NSEvent* mpLastEvent; + BOOL mbNeedSpecialKeyHandle; + BOOL mbInKeyInput; + BOOL mbKeyHandled; + NSRange mMarkedRange; + NSRange mSelectedRange; + id mpMouseEventListener; + id mDraggingDestinationHandler; + NSEvent* mpLastSuperEvent; + + // #i102807# used by magnify event handler + NSTimeInterval mfLastMagnifyTime; + float mfMagnifyDeltaSum; +} ++(void)unsetMouseFrame: (AquaSalFrame*)pFrame; +-(id)initWithSalFrame: (AquaSalFrame*)pFrame; +-(AquaSalFrame*)getSalFrame; +-(BOOL)acceptsFirstResponder; +-(BOOL)acceptsFirstMouse: (NSEvent *)pEvent; +-(BOOL)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:(sal_uInt16)nButton eventtype:(SalEvent)nEvent; +-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar; +-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod; +-(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod; +-(BOOL)sendSingleCharacter:(NSEvent*)pEvent; +-(BOOL)handleKeyDownException:(NSEvent*)pEvent; +-(void)clearLastEvent; +/* + text action methods +*/ +-(void)insertText:(id)aString replacementRange:(NSRange)replacementRange; +-(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; +-(css::accessibility::XAccessibleContext *)accessibleContext; +-(id)parentAttribute; +-(NSWindow*)windowForParent; +/* + 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 an 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 )sender; +-(NSDragOperation)draggingUpdated:(id )sender; +-(void)draggingExited:(id )sender; +-(BOOL)prepareForDragOperation:(id )sender; +-(BOOL)performDragOperation:(id )sender; +-(void)concludeDragOperation:(id )sender; + +-(void)registerDraggingDestinationHandler:(id)theHandler; +-(void)unregisterDraggingDestinationHandler:(id)theHandler; + +@end + +#endif // INCLUDED_VCL_INC_OSX_SALFRAMEVIEW_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salinst.h b/vcl/inc/osx/salinst.h new file mode 100644 index 000000000..edece53b6 --- /dev/null +++ b/vcl/inc/osx/salinst.h @@ -0,0 +1,162 @@ + +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALINST_H +#define INCLUDED_VCL_INC_OSX_SALINST_H + +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef MACOSX +#include +#endif +#include + +#include + +#include + +class AquaSalFrame; +class SalFrame; +class SalObject; +class ApplicationEvent; +class Image; +enum class SalEvent; + +typedef void(^RuninmainBlock)(void); + +class SalYieldMutex : public comphelper::SolarMutex +{ +public: + OSX_RUNINMAIN_MEMBERS + +protected: + virtual void doAcquire( sal_uInt32 nLockCount ) override; + virtual sal_uInt32 doRelease( bool bUnlockAll ) override; + +public: + SalYieldMutex(); + virtual ~SalYieldMutex() override; + + virtual bool IsCurrentThread() const override; +}; + +class AquaSalInstance : public SalInstance, public SalUserEventList +{ + friend class AquaSalFrame; + + bool RunInMainYield( bool bHandleAllCurrentEvents ); + + virtual void ProcessEvent( SalUserEvent aEvent ) override; + +public: + virtual void TriggerUserEventProcessing() override; + + OUString maDefaultPrinter; + oslThreadIdentifier maMainThread; + int mnActivePrintJobs; + osl::Mutex maUserEventListMutex; + osl::Condition maWaitingYieldCond; + bool mbIsLiveResize; + bool mbNoYieldLock; + bool mbTimerProcessed; + + static std::list aAppEventList; + + AquaSalInstance(); + virtual ~AquaSalInstance() override; + + virtual void AfterAppInit() override; + virtual bool SVMainHook(int *) override; + + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + virtual void DestroyFrame( SalFrame* pFrame ) override; + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, + bool bShow ) override; + virtual void DestroyObject( SalObject* pObject ) override; + virtual std::unique_ptr + CreateVirtualDevice( SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, + const SystemGraphicsData *pData = nullptr ) override; + virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) override; + virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ) override; + virtual std::unique_ptr CreatePrinter( SalInfoPrinter* pInfoPrinter ) override; + virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ) override; + virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) override; + virtual OUString GetDefaultPrinter() override; + virtual SalTimer* CreateSalTimer() override; + virtual SalSystem* CreateSalSystem() override; + virtual std::shared_ptr CreateSalBitmap() override; + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput( VclInputFlags nType ) override; + virtual std::unique_ptr CreateMenu( bool bMenuBar, Menu* pVCLMenu ) override; + virtual std::unique_ptr CreateMenuItem( const SalItemParams & rItemData ) override; + virtual OpenGLContext* CreateOpenGLContext() override; + virtual OUString GetConnectionIdentifier() override; + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, + const OUString& rDocumentService) override; + + virtual OUString getOSVersion() override; + + // dtrans implementation + virtual css::uno::Reference< css::uno::XInterface > CreateClipboard( + const css::uno::Sequence< css::uno::Any >& i_rArguments ) override; + virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override; + virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override; + + 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 OUString& ); + + void delayedSettingsChanged( bool bInvalidate ); + + // Is this the NSAppThread? + virtual bool IsMainThread() const override; + + void startedPrintJob() { mnActivePrintJobs++; } + void endedPrintJob() { mnActivePrintJobs--; } + + // event subtypes for NSApplicationDefined events + static const short AppExecuteSVMain = 1; + static const short AppStartTimerEvent = 10; + static const short YieldWakeupEvent = 20; + static const short DispatchTimerEvent = 30; + + static NSMenu* GetDynamicDockMenu(); +}; + +CGImageRef CreateCGImage( const Image& ); +NSImage* CreateNSImage( const Image& ); + +#endif // INCLUDED_VCL_INC_OSX_SALINST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salmenu.h b/vcl/inc/osx/salmenu.h new file mode 100644 index 000000000..597180cc1 --- /dev/null +++ b/vcl/inc/osx/salmenu.h @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALMENU_H +#define INCLUDED_VCL_INC_OSX_SALMENU_H + +#include +#include +#include + +#include + +#include + +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( sal_uInt16 i_nItemId ); + static void statusLayout(); +public: + AquaSalMenu( bool bMenuBar ); + virtual ~AquaSalMenu() override; + + virtual bool VisibleMenuBar() override; + + virtual void InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) override; + virtual void RemoveItem( unsigned nPos ) override; + virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) override; + virtual void SetFrame( const SalFrame* pFrame ) override; + virtual void CheckItem( unsigned nPos, bool bCheck ) override; + virtual void EnableItem( unsigned nPos, bool bEnable ) override; + virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText ) override; + virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage) override; + virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) override; + virtual void GetSystemMenuData( SystemMenuData* pData ) override; + virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override; + virtual bool AddMenuBarButton( const SalMenuButtonItem& ) override; + virtual void RemoveMenuBarButton( sal_uInt16 nId ) override; + virtual tools::Rectangle GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame ) override; + + int getItemIndexByPos( sal_uInt16 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 + VclPtr 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() override; + + sal_uInt16 mnId; // Item ID + VclPtr 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 // INCLUDED_VCL_INC_OSX_SALMENU_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salnativewidgets.h b/vcl/inc/osx/salnativewidgets.h new file mode 100644 index 000000000..3fdcdc40c --- /dev/null +++ b/vcl/inc/osx/salnativewidgets.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALNATIVEWIDGETS_H +#define INCLUDED_VCL_INC_OSX_SALNATIVEWIDGETS_H + +#define TAB_HEIGHT 20 // height of tab header in pixels +#define TAB_TEXT_MARGIN 12 // left/right margin of text within tab headers +#define VCL_TAB_TEXT_SEPARATOR 2 // Space between two tabs required by VCL + +#define FOCUS_RING_WIDTH 4 // width of focus ring in pixels + +#define MEDIUM_PROGRESS_INDICATOR_HEIGHT 10 // height of medium progress indicator in pixels +#define LARGE_PROGRESS_INDICATOR_HEIGHT 16 // height of large progress indicator in pixels + +#define PUSH_BUTTON_NORMAL_HEIGHT 21 // height of normal push button without focus ring in pixels +#define PUSH_BUTTON_SMALL_HEIGHT 15 // height of small push button without focus ring in pixels + +#define RADIO_BUTTON_SMALL_SIZE 14 // width/height of small radio button without focus ring in pixels +#define RADIO_BUTTON_TEXT_SEPARATOR 3 // space between radio button and following text in pixels + +#define CHECKBOX_SMALL_SIZE 14 // width/height of checkbox without focus ring in pixels +#define CHECKBOX_TEXT_SEPARATOR 3 // space between checkbox and following text in pixels + +#define SLIDER_WIDTH 19 // width of slider in pixels +#define SLIDER_HEIGHT 18 // height of slider in pixels + +#define EDITBOX_HEIGHT 21 // height of editbox without focus ring in pixels +#define EDITBOX_BORDER_WIDTH 1 // width of editbox border in pixels +#define EDITBOX_INSET_MARGIN 1 // width of left/right as well as top/bottom editbox margin in pixels + +#define COMBOBOX_HEIGHT 20 // height of combobox without focus ring in pixels +#define COMBOBOX_BUTTON_WIDTH 18 // width of combobox button without focus ring in pixels +#define COMBOBOX_BORDER_WIDTH 1 // width of combobox border in pixels +#define COMBOBOX_TEXT_MARGIN 1 // left/right margin of text in pixels + +#define LISTBOX_HEIGHT 20 // height of listbox without focus ring in pixels +#define LISTBOX_BUTTON_WIDTH 18 // width of listbox button without focus ring in pixels +#define LISTBOX_BORDER_WIDTH 1 // width of listbox border in pixels +#define LISTBOX_TEXT_MARGIN 1 // left/right margin of text in pixels + +#define SPIN_BUTTON_WIDTH 13 // width of spin button without focus ring in pixels +#define SPIN_UPPER_BUTTON_HEIGHT 11 // height of upper spin button without focus ring in pixels +#define SPIN_LOWER_BUTTON_HEIGHT 11 // height of lower spin button without focus ring in pixels + +// FIXME: spinboxes are positioned one pixel shifted to the right by VCL. As positioning as well as size should be equal to +// corresponding editboxes, comboboxes or listboxes, positioning of spinboxes should by equal too. Issue cannot be fixed within +// native widget drawing code. As a workaround, an offset is considered for spinboxes to align spinboxes correctly. + +#define SPINBOX_OFFSET 1 // left offset for alignment with editboxes, comboboxes, and listboxes + +#endif // INCLUDED_VCL_INC_OSX_SALNATIVEWIDGETS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salnsmenu.h b/vcl/inc/osx/salnsmenu.h new file mode 100644 index 000000000..f815c14c0 --- /dev/null +++ b/vcl/inc/osx/salnsmenu.h @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALNSMENU_H +#define INCLUDED_VCL_INC_OSX_SALNSMENU_H + +class AquaSalMenu; +class AquaSalMenuItem; + +@interface OOStatusItemView : NSView +{ +} +-(void)drawRect: (NSRect)aRect; +-(void)layout; +-(void)mouseUp: (NSEvent *)pEvent; +@end + +@interface SalNSMenu : NSMenu +{ + AquaSalMenu* mpMenu; +} +-(id)initWithMenu: (AquaSalMenu*)pMenu; +-(void)menuNeedsUpdate: (NSMenu*)pMenu; +-(void)setSalMenu: (AquaSalMenu*)pMenu; +@end + +@interface SalNSMenuItem : NSMenuItem +{ + AquaSalMenuItem* mpMenuItem; +} +-(id)initWithMenuItem: (AquaSalMenuItem*)pMenuItem; +-(void)menuItemTriggered: (id)aSender; +@end + +#endif // INCLUDED_VCL_INC_OSX_SALNSMENU_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salnstimer.h b/vcl/inc/osx/salnstimer.h new file mode 100644 index 000000000..d1928fe9d --- /dev/null +++ b/vcl/inc/osx/salnstimer.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALNSTIMER_H +#define INCLUDED_VCL_INC_OSX_SALNSTIMER_H + +#include +#include +#include + +@interface TimerCallbackCaller : NSObject +{ +} +-(void)timerElapsed:(NSTimer*)pTimer; +@end + +#endif // INCLUDED_VCL_INC_OSX_SALNSTIMER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salobj.h b/vcl/inc/osx/salobj.h new file mode 100644 index 000000000..17f5374d1 --- /dev/null +++ b/vcl/inc/osx/salobj.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALOBJ_H +#define INCLUDED_VCL_INC_OSX_SALOBJ_H + +#include +#include + +class AquaSalFrame; +class AquaSalObject; + + +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, SystemWindowData const * pWinData ); + virtual ~AquaSalObject() override; + + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + virtual void EndSetClipRegion() override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + virtual const SystemEnvData* GetSystemData() const override; +}; + +#endif // INCLUDED_VCL_INC_OSX_SALOBJ_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salprn.h b/vcl/inc/osx/salprn.h new file mode 100644 index 000000000..0c7ec1e9e --- /dev/null +++ b/vcl/inc/osx/salprn.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALPRN_H +#define INCLUDED_VCL_INC_OSX_SALPRN_H + +#include + +#include + +#include + +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 + std::unique_ptr mpContextMemory; + + // 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() override; + + void SetupPrinterGraphics( CGContextRef i_xContext ) const; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* i_pGraphics ) override; + virtual bool Setup( weld::Window* i_pFrame, ImplJobSetup* i_pSetupData ) override; + virtual bool SetPrinterData( ImplJobSetup* pSetupData ) override; + virtual bool SetData( JobSetFlags i_nFlags, ImplJobSetup* i_pSetupData ) override; + virtual void GetPageInfo( const ImplJobSetup* i_pSetupData, + long& o_rOutWidth, long& o_rOutHeight, + Point& rPageOffset, + Size& rPaperSize ) override; + virtual sal_uInt32 GetCapabilities( const ImplJobSetup* i_pSetupData, PrinterCapType i_nType ) override; + virtual sal_uInt16 GetPaperBinCount( const ImplJobSetup* i_pSetupData ) override; + virtual OUString GetPaperBinName( const ImplJobSetup* i_pSetupData, sal_uInt16 i_nPaperBin ) override; + virtual void InitPaperFormats( const ImplJobSetup* i_pSetupData ) override; + virtual int GetLandscapeAngle( const ImplJobSetup* i_pSetupData ) override; + + // 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 OUString* i_pFileName, + const OUString& rJobName, + const OUString& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rController ); + bool EndJob(); + bool AbortJob(); + SalGraphics* StartPage( ImplJobSetup* i_pSetupData, bool i_bNewJobData ); + bool EndPage(); + + 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& ) = delete; + AquaSalInfoPrinter& operator=(const AquaSalInfoPrinter&) = delete; +}; + + +class AquaSalPrinter : public SalPrinter +{ + AquaSalInfoPrinter* mpInfoPrinter; // pointer to the compatible InfoPrinter + public: + AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ); + virtual ~AquaSalPrinter() override; + + virtual bool StartJob( const OUString* i_pFileName, + const OUString& i_rJobName, + const OUString& i_rAppName, + sal_uInt32 i_nCopies, + bool i_bCollate, + bool i_bDirect, + ImplJobSetup* i_pSetupData ) override; + // implement pull model print system + virtual bool StartJob( const OUString* i_pFileName, + const OUString& rJobName, + const OUString& i_rAppName, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rListener ) override; + + virtual bool EndJob() override; + virtual SalGraphics* StartPage( ImplJobSetup* i_pSetupData, bool i_bNewJobData ) override; + virtual void EndPage() override; + + private: + AquaSalPrinter( const AquaSalPrinter& ) = delete; + AquaSalPrinter& operator=(const AquaSalPrinter&) = delete; +}; + +const double fPtTo100thMM = 35.27777778; + +inline int PtTo10Mu( double nPoints ) { return static_cast((nPoints*fPtTo100thMM)+0.5); } + +inline double TenMuToPt( double nUnits ) { return floor((nUnits/fPtTo100thMM)+0.5); } + +#endif // INCLUDED_VCL_INC_OSX_SALPRN_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/salsys.h b/vcl/inc/osx/salsys.h new file mode 100644 index 000000000..b0bc98578 --- /dev/null +++ b/vcl/inc/osx/salsys.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALSYS_H +#define INCLUDED_VCL_INC_OSX_SALSYS_H + +#include + +#include + + +class VCL_DLLPUBLIC AquaSalSystem : public SalSystem +{ +public: + AquaSalSystem() {} + virtual ~AquaSalSystem() override; + + // get info about the display + virtual unsigned int GetDisplayScreenCount() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ) override; + + virtual int ShowNativeMessageBox( const OUString& rTitle, + const OUString& rMessage) override; +}; + +#endif // INCLUDED_VCL_INC_OSX_SALSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/saltimer.h b/vcl/inc/osx/saltimer.h new file mode 100644 index 000000000..cdde3ec84 --- /dev/null +++ b/vcl/inc/osx/saltimer.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SALTIMER_H +#define INCLUDED_VCL_INC_OSX_SALTIMER_H + +#include +#include +#include + +#include + +/** + * if NO == bAtStart, then it has to be run in the main thread, + * e.g. via performSelectorOnMainThread! + **/ +void ImplNSAppPostEvent( short nEventId, BOOL bAtStart, int nUserData = 0 ); + +class ReleasePoolHolder +{ + NSAutoreleasePool* mpPool; + +public: + ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} + ~ReleasePoolHolder() { [mpPool release]; } +}; + +class AquaSalTimer final : public SalTimer, protected VersionedEvent +{ + NSTimer *m_pRunningTimer; + bool m_bDirectTimeout; ///< timeout can be processed directly + + void queueDispatchTimerEvent( bool bAtStart ); + void callTimerCallback(); + +public: + AquaSalTimer(); + virtual ~AquaSalTimer() override; + + void Start( sal_uInt64 nMS ) override; + void Stop() override; + + void handleStartTimerEvent( NSEvent* pEvent ); + bool handleDispatchTimerEvent( NSEvent* pEvent ); + void handleTimerElapsed(); + void handleWindowShouldClose(); + + bool IsTimerElapsed() const; + inline bool IsDirectTimeout() const; +}; + +inline bool AquaSalTimer::IsDirectTimeout() const +{ + return m_bDirectTimeout; +} + +#endif // INCLUDED_VCL_INC_OSX_SALTIMER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/svsys.h b/vcl/inc/osx/svsys.h new file mode 100644 index 000000000..9fcabe074 --- /dev/null +++ b/vcl/inc/osx/svsys.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_SVSYS_H +#define INCLUDED_VCL_INC_OSX_SVSYS_H + +#include +#include +#include + +#endif // INCLUDED_VCL_INC_OSX_SVSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/osx/vclnsapp.h b/vcl/inc/osx/vclnsapp.h new file mode 100644 index 000000000..82f0229a9 --- /dev/null +++ b/vcl/inc/osx/vclnsapp.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OSX_VCLNSAPP_H +#define INCLUDED_VCL_INC_OSX_VCLNSAPP_H + +#include + +#include +#include +#include + +class AquaSalFrame; + +@interface CocoaThreadEnabler : NSObject +{ +} +-(void)enableCocoaThreads:(id)param; +@end + +// our very own application +@interface VCL_NSApplication : NSApplication +{ +} +-(void)applicationDidFinishLaunching:(NSNotification*)pNotification; +-(void)sendEvent:(NSEvent*)pEvent; +-(void)sendSuperEvent:(NSEvent*)pEvent; +-(NSMenu*)applicationDockMenu:(NSApplication *)sender; +-(BOOL)application: (NSApplication*) app openFile: (NSString*)file; +-(void)application: (NSApplication*) app openFiles: (NSArray*)files; +-(BOOL)application: (NSApplication*) app printFile: (NSString*)file; +-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(BOOL)bShowPrintPanels; +-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app; +-(void)applicationWillTerminate: (NSNotification *) aNotification; +-(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; +#if !HAVE_FEATURE_MACOSX_SANDBOX +-(void)applicationWillBecomeActive: (NSNotification *)pNotification; +-(void)applicationWillResignActive: (NSNotification *)pNotification; +#endif +-(BOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (BOOL)bWinVisible; +-(void)setDockIconClickHandler: (NSObject*)pHandler; +@end + +#endif // INCLUDED_VCL_INC_OSX_VCLNSAPP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/outdata.hxx b/vcl/inc/outdata.hxx new file mode 100644 index 000000000..9764a6cda --- /dev/null +++ b/vcl/inc/outdata.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OUTDATA_HXX +#define INCLUDED_VCL_INC_OUTDATA_HXX + +#include + +inline bool ImplIsColorTransparent( Color aColor ) +{ + return aColor.GetTransparency() != 0; +} + +#endif // INCLUDED_VCL_INC_OUTDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/outdev.h b/vcl/inc/outdev.h new file mode 100644 index 000000000..27f8dc548 --- /dev/null +++ b/vcl/inc/outdev.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OUTDEV_H +#define INCLUDED_VCL_INC_OUTDEV_H + +#include +#include + +#include +#include + +#include "fontinstance.hxx" +#include "PhysicalFontFace.hxx" +#include "impfontcache.hxx" + +class Size; +namespace vcl { class Font; } +class VirtualDevice; +class PhysicalFontCollection; +enum class AddFontSubstituteFlags; + +// an ImplDeviceFontList is created by a PhysicalFontCollection +// it becomes invalid when original PhysicalFontCollection is modified +class ImplDeviceFontList +{ +private: + std::vector> maDevFontVector; + +public: + ImplDeviceFontList() { maDevFontVector.reserve(1024); } + void Add( PhysicalFontFace* pFace ) { maDevFontVector.push_back( pFace ); } + PhysicalFontFace* Get( int nIndex ) const { return maDevFontVector[ nIndex ].get(); } + int Count() const { return maDevFontVector.size(); } +}; + +class ImplDeviceFontSizeList +{ +private: + std::vector maSizeList; + +public: + ImplDeviceFontSizeList() + { 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 ]; } +}; + +// 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 class 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 +{ + OUString maSearchName; + OUString maSearchReplaceName; + AddFontSubstituteFlags mnFlags; + + ImplFontSubstEntry( const OUString& rFontName, const OUString& rSubstFontName, AddFontSubstituteFlags nSubstFlags ); +}; + +class ImplDirectFontSubstitution final +: public ImplFontSubstitution +{ +private: + std::vector maFontSubstList; +public: + void AddFontSubstitute( const OUString& rFontName, const OUString& rSubstName, AddFontSubstituteFlags nFlags ); + void RemoveFontsSubstitute(); + + bool FindFontSubstitute( OUString& rSubstName, const OUString& rFontName ) 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(FontSelectPattern&) const = 0; +}; + +// ImplGlyphFallbackFontSubstitution +// abstracts the concept of finding the best font to support an incomplete font +class ImplGlyphFallbackFontSubstitution +: public ImplFontSubstitution +{ +public: + virtual bool FindFontSubstitute(FontSelectPattern&, LogicalFontInstance* pLogicalFont, OUString& rMissingCodes) const = 0; +}; + +namespace vcl { struct ControlLayoutData; } +// #i75163# +namespace basegfx { class B2DHomMatrix; } + +struct ImplOutDevData +{ + VclPtr mpRotateDev; + vcl::ControlLayoutData* mpRecordLayout; + tools::Rectangle maRecordRect; + + // #i75163# + basegfx::B2DHomMatrix* mpViewTransform; + basegfx::B2DHomMatrix* mpInverseViewTransform; +}; + +void ImplFontSubstitute( OUString& rFontName ); + +#endif // INCLUDED_VCL_INC_OUTDEV_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pch/precompiled_vcl.cxx b/vcl/inc/pch/precompiled_vcl.cxx new file mode 100644 index 000000000..79285a8f9 --- /dev/null +++ b/vcl/inc/pch/precompiled_vcl.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "precompiled_vcl.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pch/precompiled_vcl.hxx b/vcl/inc/pch/precompiled_vcl.hxx new file mode 100644 index 000000000..2e94519a4 --- /dev/null +++ b/vcl/inc/pch/precompiled_vcl.hxx @@ -0,0 +1,340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + This file has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-05-07 20:21:38 using: + ./bin/update_pch vcl vcl --cutoff=6 --exclude:system --include:module --include:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./vcl/inc/pch/precompiled_vcl.hxx "make vcl.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/BitmapID.hxx b/vcl/inc/pdf/BitmapID.hxx new file mode 100644 index 000000000..cedc57903 --- /dev/null +++ b/vcl/inc/pdf/BitmapID.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_PDF_BITMAPID_HXX +#define INCLUDED_VCL_INC_PDF_BITMAPID_HXX + +#include +#include +#include + +namespace vcl::pdf +{ +struct BitmapID +{ + Size m_aPixelSize; + sal_Int32 m_nSize; + BitmapChecksum m_nChecksum; + BitmapChecksum m_nMaskChecksum; + + BitmapID() + : m_nSize(0) + , m_nChecksum(0) + , m_nMaskChecksum(0) + { + } + + bool operator==(const BitmapID& rComp) const + { + return (m_aPixelSize == rComp.m_aPixelSize && m_nSize == rComp.m_nSize + && m_nChecksum == rComp.m_nChecksum && m_nMaskChecksum == rComp.m_nMaskChecksum); + } +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/Matrix3.hxx b/vcl/inc/pdf/Matrix3.hxx new file mode 100644 index 000000000..c36332015 --- /dev/null +++ b/vcl/inc/pdf/Matrix3.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_PDF_MATRIX3_HXX +#define INCLUDED_VCL_INC_PDF_MATRIX3_HXX + +#include +#include + +namespace vcl::pdf +{ +// matrix helper class +// TODO: use basegfx matrix class instead or derive from it + +/* 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(const double* pn) + { + for (int i = 0; i < 6; i++) + f[i] = pn[i]; + } + +public: + Matrix3(); + + void skew(double alpha, double beta); + void scale(double sx, double sy); + void rotate(double angle); + void translate(double tx, double ty); + void invert(); + + double get(size_t i) const { return f[i]; } + + Point transform(const Point& rPoint) const; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/ResourceDict.hxx b/vcl/inc/pdf/ResourceDict.hxx new file mode 100644 index 000000000..488a821db --- /dev/null +++ b/vcl/inc/pdf/ResourceDict.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_PDF_RESOURCEDICT_HXX +#define INCLUDED_VCL_INC_PDF_RESOURCEDICT_HXX + +#include +#include +#include + +namespace vcl::pdf +{ +enum class ResourceKind +{ + XObject, + ExtGState, + Shading, + Pattern +}; + +struct ResourceDict +{ + // note: handle fonts globally for performance + std::map m_aXObjects; + std::map m_aExtGStates; + std::map m_aShadings; + std::map m_aPatterns; + + void append(OStringBuffer& rBuffer, sal_Int32 nFontDictObject); +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/pdf/XmpMetadata.hxx b/vcl/inc/pdf/XmpMetadata.hxx new file mode 100644 index 000000000..61438e0e5 --- /dev/null +++ b/vcl/inc/pdf/XmpMetadata.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_PDF_XMPMETADATA_HXX +#define INCLUDED_VCL_INC_PDF_XMPMETADATA_HXX + +#include +#include +#include +#include + +namespace vcl::pdf +{ +class XmpMetadata +{ +private: + bool mbWritten; + std::unique_ptr mpMemoryStream; + +public: + OString msTitle; + OString msAuthor; + OString msSubject; + OString msProducer; + OString msKeywords; + OString m_sCreatorTool; + OString m_sCreateDate; + + sal_Int32 mnPDF_A; + bool mbPDF_UA; + +public: + XmpMetadata(); + sal_uInt64 getSize(); + const void* getData(); + +private: + void write(); +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ppdparser.hxx b/vcl/inc/ppdparser.hxx new file mode 100644 index 000000000..b5bf309ed --- /dev/null +++ b/vcl/inc/ppdparser.hxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_PPDPARSER_HXX +#define INCLUDED_VCL_PPDPARSER_HXX + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define PRINTER_PPDDIR "driver" + +namespace psp { + +class PPDCache; +class PPDTranslator; + +enum PPDValueType { eInvocation, eQuoted, eSymbol, eString, eNo }; + +struct VCL_DLLPUBLIC PPDValue +{ + PPDValueType m_eType; + //CustomOption stuff for fdo#43049 + //see http://www.cups.org/documentation.php/spec-ppd.html#OPTIONS + //for full specs, only the basics are implemented here + bool m_bCustomOption; + mutable OUString m_aCustomOption; + OUString m_aOption; + OUString m_aValue; +}; + + +/* + * PPDKey - a container for the available options (=values) of a PPD keyword + */ + +class PPDKey +{ + friend class PPDParser; + friend class CPDManager; + + typedef std::unordered_map< OUString, PPDValue > hash_type; + typedef std::vector< PPDValue* > value_type; + + OUString m_aKey; + hash_type m_aValues; + value_type m_aOrderedValues; + const PPDValue* m_pDefaultValue; + bool m_bQueryValue; + OUString m_aGroup; + +public: + enum class SetupType { ExitServer, Prolog, DocumentSetup, PageSetup, JCLSetup, AnySetup }; +private: + + bool m_bUIOption; + int m_nOrderDependency; + SetupType m_eSetupType; + + void eraseValue( const OUString& rOption ); +public: + PPDKey( const OUString& rKey ); + ~PPDKey(); + + PPDValue* insertValue(const OUString& rOption, PPDValueType eType, bool bCustomOption = false); + int countValues() const + { return m_aValues.size(); } + // neither getValue will return the query option + const PPDValue* getValue( int n ) const; + const PPDValue* getValue( const OUString& rOption ) const; + const PPDValue* getValueCaseInsensitive( const OUString& rOption ) const; + const PPDValue* getDefaultValue() const { return m_pDefaultValue; } + const OUString& getGroup() const { return m_aGroup; } + + const OUString& getKey() const { return m_aKey; } + bool isUIKey() const { return m_bUIOption; } + 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 reinterpret_cast(pKey); } +}; + + +/* + * PPDParser - parses a PPD file and contains all available keys from it + */ + +class PPDParser +{ + friend class PPDContext; + friend class CUPSManager; + friend class CPDManager; + friend class PPDCache; + + typedef std::unordered_map< OUString, std::unique_ptr > hash_type; + typedef std::vector< PPDKey* > value_type; + + void insertKey( std::unique_ptr pKey ); +public: + struct PPDConstraint + { + const PPDKey* m_pKey1; + const PPDValue* m_pOption1; + const PPDKey* m_pKey2; + const PPDValue* m_pOption2; + + PPDConstraint() : m_pKey1( nullptr ), m_pOption1( nullptr ), m_pKey2( nullptr ), m_pOption2( nullptr ) {} + }; +private: + hash_type m_aKeys; + value_type m_aOrderedKeys; + ::std::vector< PPDConstraint > m_aConstraints; + + // the full path of the PPD file + OUString m_aFile; + // some basic attributes + bool m_bColorDevice; + bool m_bType42Capable; + sal_uLong m_nLanguageLevel; + rtl_TextEncoding m_aFileEncoding; + + + // shortcuts to important keys and their default values + // imageable area + const PPDKey* m_pImageableAreas; + // paper dimensions + const PPDValue* m_pDefaultPaperDimension; + const PPDKey* m_pPaperDimensions; + // paper trays + const PPDValue* m_pDefaultInputSlot; + // resolutions + const PPDValue* m_pDefaultResolution; + + // translations + std::unique_ptr m_pTranslator; + + PPDParser( const OUString& rFile ); + PPDParser(const OUString& rFile, const std::vector& keys); + + void parseOrderDependency(const OString& rLine); + void parseOpenUI(const OString& rLine, const OString& rPPDGroup); + void parseConstraint(const OString& rLine); + void parse( std::vector< OString >& rLines ); + + OUString handleTranslation(const OString& i_rString, bool i_bIsGlobalized); + + static void scanPPDDir( const OUString& rDir ); + static void initPPDFiles(PPDCache &rPPDCache); + static OUString getPPDFile( const OUString& rFile ); +public: + ~PPDParser(); + static const PPDParser* getParser( const OUString& rFile ); + + const PPDKey* getKey( int n ) const; + const PPDKey* getKey( const OUString& rKey ) const; + int getKeys() const { return m_aKeys.size(); } + bool hasKey( const PPDKey* ) const; + + const ::std::vector< PPDConstraint >& getConstraints() const { return m_aConstraints; } + + bool isColorDevice() const { return m_bColorDevice; } + bool isType42Capable() const { return m_bType42Capable; } + sal_uLong getLanguageLevel() const { return m_nLanguageLevel; } + + OUString getDefaultPaperDimension() const; + void getDefaultPaperDimension( int& rWidth, int& rHeight ) const + { getPaperDimension( getDefaultPaperDimension(), rWidth, rHeight ); } + bool getPaperDimension( const OUString& rPaperName, + int& rWidth, int& rHeight ) const; + // width and height in pt + // returns false if paper not found + + // match the best paper for width and height + OUString matchPaper( int nWidth, int nHeight ) const; + + bool getMargins( const OUString& rPaperName, + int &rLeft, int& rRight, + int &rUpper, int& rLower ) const; + // values in pt + // returns true if paper found + + // values int pt + + OUString getDefaultInputSlot() const; + + void getDefaultResolution( int& rXRes, int& rYRes ) const; + // values in dpi + static void getResolutionFromString( const OUString&, int&, int& ); + // helper function + + OUString translateKey( const OUString& i_rKey ) const; + OUString translateOption( const OUString& i_rKey, + const OUString& i_rOption ) const; +}; + + +/* + * PPDContext - a class to manage user definable states based on the + * contents of a PPDParser. + */ + +class PPDContext +{ + typedef std::unordered_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 succeeded, new value can be set + bool checkConstraints( const PPDKey*, const PPDValue*, bool bDoReset ); + bool resetValue( const PPDKey*, bool bDefaultable = false ); +public: + PPDContext(); + PPDContext( const PPDContext& rContext ) { operator=( rContext ); } + PPDContext& operator=( const PPDContext& rContext ) = default; + PPDContext& operator=( PPDContext&& rContext ); + + 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 ); + + std::size_t countValuesModified() const { return m_aCurrentValues.size(); } + const PPDKey* getModifiedKey( std::size_t n ) const; + + // public wrapper for the private method + bool checkConstraints( const PPDKey*, const PPDValue* ); + + // for printer setup + char* getStreamableBuffer( sal_uLong& rBytes ) const; + void rebuildFromStreamBuffer(const std::vector &rBuffer); + + // convenience + int getRenderResolution() const; + + // width, height in points, paper will contain the name of the selected + // paper after the call + void getPageSize( OUString& rPaper, int& rWidth, int& rHeight ) const; +}; + +} // namespace + +#endif // INCLUDED_VCL_PPDPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/print.h b/vcl/inc/print.h new file mode 100644 index 000000000..13650ceef --- /dev/null +++ b/vcl/inc/print.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PRINT_H +#define INCLUDED_VCL_INC_PRINT_H + +#include +#include +#include +#include "salprn.hxx" + +#include +#include + +class JobSetup; + +namespace vcl +{ class PrinterListener; } + +struct ImplPrnQueueData +{ + std::unique_ptr mpQueueInfo; + std::unique_ptr mpSalQueueInfo; + +// unlike other similar places, we need to ifdef this to keep old GCC baseline happy +#ifdef _MSC_VER + ImplPrnQueueData() {} + ImplPrnQueueData(ImplPrnQueueData&&) = default; + + ImplPrnQueueData& operator=( ImplPrnQueueData const & ) = delete; // MSVC2017 workaround + ImplPrnQueueData( ImplPrnQueueData const & ) = delete; // MSVC2017 workaround +#endif +}; + +class VCL_PLUGIN_PUBLIC ImplPrnQueueList +{ +public: + std::unordered_map< OUString, sal_Int32 > m_aNameToIndex; + std::vector< ImplPrnQueueData > m_aQueueInfos; + std::vector< OUString > m_aPrinterList; + + ImplPrnQueueList() {} + ~ImplPrnQueueList(); + + ImplPrnQueueList& operator=( ImplPrnQueueList const & ) = delete; // MSVC2017 workaround + ImplPrnQueueList( ImplPrnQueueList const & ) = delete; // MSVC2017 workaround + +void Add( std::unique_ptr pData ); + ImplPrnQueueData* Get( const OUString& rPrinter ); +}; + +void ImplDeletePrnQueueList(); +void ImplUpdateJobSetupPaper( JobSetup& rJobSetup ); + +#endif // INCLUDED_VCL_INC_PRINT_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/print.hrc b/vcl/inc/print.hrc new file mode 100644 index 000000000..91c11309a --- /dev/null +++ b/vcl/inc/print.hrc @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PRINT_HRC +#define INCLUDED_VCL_INC_PRINT_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +const char* RID_STR_PAPERNAMES[] = +{ + // To translators: This is the first entry of a sequence of paper size names + NC_("RID_STR_PAPERNAMES", "A0"), + NC_("RID_STR_PAPERNAMES", "A1"), + NC_("RID_STR_PAPERNAMES", "A2"), + NC_("RID_STR_PAPERNAMES", "A3"), + NC_("RID_STR_PAPERNAMES", "A4"), + NC_("RID_STR_PAPERNAMES", "A5"), + NC_("RID_STR_PAPERNAMES", "B4 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B5 (ISO)"), + NC_("RID_STR_PAPERNAMES", "Letter"), + NC_("RID_STR_PAPERNAMES", "Legal"), + NC_("RID_STR_PAPERNAMES", "Tabloid"), + NC_("RID_STR_PAPERNAMES", "User Defined"), + NC_("RID_STR_PAPERNAMES", "B6 (ISO)"), + NC_("RID_STR_PAPERNAMES", "C4 Envelope"), + NC_("RID_STR_PAPERNAMES", "C5 Envelope"), + NC_("RID_STR_PAPERNAMES", "C6 Envelope"), + NC_("RID_STR_PAPERNAMES", "C6/5 Envelope"), + NC_("RID_STR_PAPERNAMES", "DL Envelope"), + NC_("RID_STR_PAPERNAMES", "Dia Slide"), + NC_("RID_STR_PAPERNAMES", "Screen 4:3"), + NC_("RID_STR_PAPERNAMES", "C"), + NC_("RID_STR_PAPERNAMES", "D"), + NC_("RID_STR_PAPERNAMES", "E"), + NC_("RID_STR_PAPERNAMES", "Executive"), + NC_("RID_STR_PAPERNAMES", "German Legal Fanfold"), + NC_("RID_STR_PAPERNAMES", "#8 (Monarch) Envelope"), + NC_("RID_STR_PAPERNAMES", "#6 3/4 (Personal) Envelope"), + NC_("RID_STR_PAPERNAMES", "#9 Envelope"), + NC_("RID_STR_PAPERNAMES", "#10 Envelope"), + NC_("RID_STR_PAPERNAMES", "#11 Envelope"), + NC_("RID_STR_PAPERNAMES", "#12 Envelope"), + NC_("RID_STR_PAPERNAMES", "16 Kai (16k)"), + NC_("RID_STR_PAPERNAMES", "32 Kai"), + NC_("RID_STR_PAPERNAMES", "Big 32 Kai"), + NC_("RID_STR_PAPERNAMES", "B4 (JIS)"), + NC_("RID_STR_PAPERNAMES", "B5 (JIS)"), + NC_("RID_STR_PAPERNAMES", "B6 (JIS)"), + NC_("RID_STR_PAPERNAMES", "Ledger"), + NC_("RID_STR_PAPERNAMES", "Statement"), + NC_("RID_STR_PAPERNAMES", "Quarto"), + NC_("RID_STR_PAPERNAMES", "10x14"), + NC_("RID_STR_PAPERNAMES", "#14 Envelope"), + NC_("RID_STR_PAPERNAMES", "C3 Envelope"), + NC_("RID_STR_PAPERNAMES", "Italian Envelope"), + NC_("RID_STR_PAPERNAMES", "U.S. Standard Fanfold"), + NC_("RID_STR_PAPERNAMES", "German Standard Fanfold"), + NC_("RID_STR_PAPERNAMES", "Japanese Postcard"), + NC_("RID_STR_PAPERNAMES", "9x11"), + NC_("RID_STR_PAPERNAMES", "10x11"), + NC_("RID_STR_PAPERNAMES", "15x11"), + NC_("RID_STR_PAPERNAMES", "Invitation Envelope"), + NC_("RID_STR_PAPERNAMES", "SuperA"), + NC_("RID_STR_PAPERNAMES", "SuperB"), + NC_("RID_STR_PAPERNAMES", "Letter Plus"), + NC_("RID_STR_PAPERNAMES", "A4 Plus"), + NC_("RID_STR_PAPERNAMES", "Double Postcard"), + NC_("RID_STR_PAPERNAMES", "A6"), + NC_("RID_STR_PAPERNAMES", "12x11"), + NC_("RID_STR_PAPERNAMES", "A7"), + NC_("RID_STR_PAPERNAMES", "A8"), + NC_("RID_STR_PAPERNAMES", "A9"), + NC_("RID_STR_PAPERNAMES", "A10"), + NC_("RID_STR_PAPERNAMES", "B0 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B1 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B2 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B3 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B7 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B8 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B9 (ISO)"), + NC_("RID_STR_PAPERNAMES", "B10 (ISO)"), + NC_("RID_STR_PAPERNAMES", "C2 Envelope"), + NC_("RID_STR_PAPERNAMES", "C7 Envelope"), + NC_("RID_STR_PAPERNAMES", "C8 Envelope"), + NC_("RID_STR_PAPERNAMES", "Arch A"), + NC_("RID_STR_PAPERNAMES", "Arch B"), + NC_("RID_STR_PAPERNAMES", "Arch C"), + NC_("RID_STR_PAPERNAMES", "Arch D"), + NC_("RID_STR_PAPERNAMES", "Arch E"), + NC_("RID_STR_PAPERNAMES", "Screen 16:9"), + NC_("RID_STR_PAPERNAMES", "Screen 16:10"), + NC_("RID_STR_PAPERNAMES", "16k (195 x 270)"), + // To translators: This is the last entry of the sequence of paper size names + NC_("RID_STR_PAPERNAMES", "16k (197 x 273)") +}; + +#endif // INCLUDED_VCL_INC_PRINT_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/printaccessoryview.hrc b/vcl/inc/printaccessoryview.hrc new file mode 100644 index 000000000..936c5b2bc --- /dev/null +++ b/vcl/inc/printaccessoryview.hrc @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_PRINTACCESSORYVIEW_HRC +#define INCLUDED_VCL_INC_PRINTACCESSORYVIEW_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +const char* SV_PRINT_NATIVE_STRINGS[] = +{ + NC_("SV_PRINT_NATIVE_STRINGS", "Preview"), + NC_("SV_PRINT_NATIVE_STRINGS", "Page number"), + NC_("SV_PRINT_NATIVE_STRINGS", "Number of pages"), + NC_("SV_PRINT_NATIVE_STRINGS", "More"), + NC_("SV_PRINT_NATIVE_STRINGS", "Print selection only") +}; + +#endif // INCLUDED_VCL_INC_PRINTACCESSORYVIEW_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/printdlg.hxx b/vcl/inc/printdlg.hxx new file mode 100644 index 000000000..c313e8fc4 --- /dev/null +++ b/vcl/inc/printdlg.hxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef VCL_INC_NEWPRINTDLG_HXX +#define VCL_INC_NEWPRINTDLG_HXX + +#include +#include +#include +#include +#include +#include + +namespace vcl { + class PrintDialog; +} + +namespace vcl +{ + class MoreOptionsDialog final : public weld::GenericDialogController + { + PrintDialog* mpParent; + std::unique_ptr mxOKButton; + std::unique_ptr mxCancelButton; + std::unique_ptr mxSingleJobsBox; + + DECL_LINK( ClickHdl, weld::Button&, void ); + + public: + + MoreOptionsDialog(PrintDialog* i_pParent); + virtual ~MoreOptionsDialog() override; + }; + + class PrintDialog : public weld::GenericDialogController + { + friend class MoreOptionsDialog; + public: + + class PrintPreviewWindow final : public weld::CustomWidgetController + { + PrintDialog* mpDialog; + GDIMetaFile maMtf; + Size maOrigSize; + Size maPreviewSize; + sal_Int32 mnDPIX; + sal_Int32 mnDPIY; + BitmapEx maPreviewBitmap; + OUString maReplacementString; + bool mbGreyscale; + + OUString maHorzText; + OUString maVertText; + + void preparePreviewBitmap(); + + public: + PrintPreviewWindow(PrintDialog* pDialog); + virtual ~PrintPreviewWindow() override; + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual bool Command( const CommandEvent& ) override; + virtual void Resize() override; + + void setPreview( const GDIMetaFile&, const Size& i_rPaperSize, + const OUString& i_rPaperName, + const OUString& i_rNoPageString, + sal_Int32 i_nDPIX, sal_Int32 i_nDPIY, + bool i_bGreyscale + ); + }; + + class ShowNupOrderWindow final : public weld::CustomWidgetController + { + NupOrderType mnOrderMode; + int mnRows; + int mnColumns; + public: + ShowNupOrderWindow(); + + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override; + + void setValues( NupOrderType i_nOrderMode, int i_nColumns, int i_nRows ) + { + mnOrderMode = i_nOrderMode; + mnRows = i_nRows; + mnColumns = i_nColumns; + Invalidate(); + } + }; + + PrintDialog(weld::Window*, const std::shared_ptr&); + virtual ~PrintDialog() override; + + bool isPrintToFile() const; + bool isCollate() const; + bool isSingleJobs() const { return mbSingleJobs; }; + bool hasPreview() const; + + void setPaperSizes(); + void previewForward(); + void previewBackward(); + void previewFirst(); + void previewLast(); + + private: + + std::unique_ptr mxCustomOptionsUIBuilder; + + std::shared_ptr maPController; + + std::unique_ptr mxMoreOptionsDlg; + + std::unique_ptr mxTabCtrl; + std::unique_ptr mxScrolledWindow; + std::unique_ptr mxPageLayoutFrame; + std::unique_ptr mxPrinters; + std::unique_ptr mxStatusTxt; + std::unique_ptr mxSetupButton; + + std::unique_ptr mxCopyCountField; + std::unique_ptr mxCollateBox; + std::unique_ptr mxCollateImage; + std::unique_ptr mxPageRangeEdit; + std::unique_ptr mxPageRangesRadioButton; + std::unique_ptr mxPaperSidesBox; + std::unique_ptr mxReverseOrderBox; + + std::unique_ptr mxOKButton; + std::unique_ptr mxCancelButton; + std::unique_ptr mxHelpButton; + std::unique_ptr mxMoreOptionsBtn; + + std::unique_ptr mxBackwardBtn; + std::unique_ptr mxForwardBtn; + std::unique_ptr mxFirstBtn; + std::unique_ptr mxLastBtn; + + std::unique_ptr mxPreviewBox; + std::unique_ptr mxNumPagesText; + std::unique_ptr mxPreview; + std::unique_ptr mxPreviewWindow; + std::unique_ptr mxPageEdit; + + std::unique_ptr mxPagesBtn; + std::unique_ptr mxBrochureBtn; + std::unique_ptr mxPagesBoxTitleTxt; + std::unique_ptr mxNupPagesBox; + + // controls for "Custom" page mode + std::unique_ptr mxNupNumPagesTxt; + std::unique_ptr mxNupColEdt; + std::unique_ptr mxNupTimesTxt; + std::unique_ptr mxNupRowsEdt; + std::unique_ptr mxPageMarginTxt1; + std::unique_ptr mxPageMarginEdt; + std::unique_ptr mxPageMarginTxt2; + std::unique_ptr mxSheetMarginTxt1; + std::unique_ptr mxSheetMarginEdt; + std::unique_ptr mxSheetMarginTxt2; + std::unique_ptr mxPaperSizeBox; + std::unique_ptr mxOrientationBox; + + // page order ("left to right, then down") + std::unique_ptr mxNupOrderTxt; + std::unique_ptr mxNupOrderBox; + std::unique_ptr mxNupOrder; + std::unique_ptr mxNupOrderWin; + /// border around each page + std::unique_ptr mxBorderCB; + std::unique_ptr mxRangeExpander; + std::unique_ptr mxLayoutExpander; + std::unique_ptr mxCustom; + + OUString maPrintToFileText; + OUString maPrintText; + OUString maDefPrtText; + + OUString maPageStr; + OUString maNoPageStr; + OUString maNoPreviewStr; + sal_Int32 mnCurPage; + sal_Int32 mnCachedPages; + + bool mbCollateAlwaysOff; + + std::vector> + maExtraControls; + + std::map + maControlToPropertyMap; + std::map> + maPropertyToWindowMap; + std::map + maControlToNumValMap; + + Size maNupPortraitSize; + Size maNupLandscapeSize; + /// internal, used for automatic Nup-Portrait/landscape + Size maFirstPageSize; + + bool mbShowLayoutFrame; + bool mbSingleJobs; + + Paper mePaper; + + DECL_LINK( ClickHdl, weld::Button&, void ); + DECL_LINK( SelectHdl, weld::ComboBox&, void ); + DECL_LINK( ActivateHdl, weld::Entry&, bool ); + DECL_LINK( FocusOutHdl, weld::Widget&, void ); + DECL_LINK( SpinModifyHdl, weld::SpinButton&, void ); + DECL_LINK( MetricSpinModifyHdl, weld::MetricSpinButton&, void ); + DECL_LINK( ToggleHdl, weld::ToggleButton&, void ); + + DECL_LINK( UIOption_CheckHdl, weld::ToggleButton&, void ); + DECL_LINK( UIOption_RadioHdl, weld::ToggleButton&, void ); + DECL_LINK( UIOption_SelectHdl, weld::ComboBox&, void ); + DECL_LINK( UIOption_SpinModifyHdl, weld::SpinButton&, void ); + DECL_LINK( UIOption_EntryModifyHdl, weld::Entry&, void ); + + DECL_LINK( ExpandHdl, weld::Expander&, void ); + + css::beans::PropertyValue* getValueForWindow(weld::Widget*) const; + + void preparePreview( bool i_bMayUseCache ); + void setupPaperSidesBox(); + void storeToSettings(); + void readFromSettings(); + void setPaperOrientation( Orientation eOrientation ); + void updateOrientationBox( bool bAutomatic = true ); + bool hasOrientationChanged() const; + void checkPaperSize( Size& rPaperSize ); + void setPreviewText(); + void updatePrinterText(); + void checkControlDependencies(); + void checkOptionalControlDependencies(); + void makeEnabled( weld::Widget* ); + void updateWindowFromProperty( const OUString& ); + void initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& ); + void showAdvancedControls( bool ); + void updateNup( bool i_bMayUseCache = true ); + void updateNupFromPages( bool i_bMayUseCache = true ); + void enableNupControls( bool bEnable ); + void setupOptionalUI(); + Size const & getJobPageSize(); + + }; + + class PrintProgressDialog final : public weld::GenericDialogController + { + OUString maStr; + bool mbCanceled; + sal_Int32 mnCur; + sal_Int32 mnMax; + + std::unique_ptr mxText; + std::unique_ptr mxProgress; + std::unique_ptr mxButton; + + DECL_LINK( ClickHdl, weld::Button&, void ); + + public: + PrintProgressDialog(weld::Window* i_pParent, int i_nMax); + virtual ~PrintProgressDialog() override; + bool isCanceled() const { return mbCanceled; } + void setProgress( int i_nCurrent ); + void tick(); + }; +} + +#endif // VCL_INC_NEWPRINTDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/printerinfomanager.hxx b/vcl/inc/printerinfomanager.hxx new file mode 100644 index 000000000..2286158d6 --- /dev/null +++ b/vcl/inc/printerinfomanager.hxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_PRINTERINFOMANAGER_HXX +#define INCLUDED_VCL_PRINTERINFOMANAGER_HXX + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "jobdata.hxx" + +namespace psp +{ + +class SystemQueueInfo; + +struct PrinterInfo : JobData +{ + // basename of PPD + OUString m_aDriverName; + // can be the queue + OUString m_aLocation; + // a user defined comment + OUString m_aComment; + // a command line to pipe a PS-file to + OUString m_aCommand; + // a command line to pipe a PS-file to in case of direct print + 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") + OUString m_aFeatures; + // auth-info-required, potential [domain],[username],[password] to prompt for to authenticate printing + OUString m_aAuthInfoRequired; + PrinterSetupMode meSetupMode; + + PrinterInfo() + : JobData() + , meSetupMode(PrinterSetupMode::SingleJob) + {} +}; + +class VCL_DLLPUBLIC PrinterInfoManager +{ +public: + enum class Type { Default = 0, CUPS = 1, CPD = 2 }; + + struct SystemPrintQueue + { + OUString m_aQueue; + OUString m_aLocation; + OUString m_aComment; + }; +protected: + // needed for checkPrintersChanged: files (not necessarily existent) + // and their last known modification time + struct WatchFile + { + // the file in question + 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 + OUString m_aFile; + // details other config files that have this printer + // in case of removal all have to be removed + std::unordered_set< OUString > m_aAlternateFiles; + // the corresponding info and job data + PrinterInfo m_aInfo; + }; + + std::unordered_map< OUString, Printer > m_aPrinters; + PrinterInfo m_aGlobalDefaults; + std::vector< WatchFile > m_aWatchFiles; + OUString m_aDefaultPrinter; + OUString m_aSystemPrintCommand; + + std::vector< SystemPrintQueue > m_aSystemPrintQueues; + + std::unique_ptr + m_pQueueInfo; + + Type m_eType; + bool m_bUseIncludeFeature; + bool m_bUseJobPatch; + OUString m_aSystemDefaultPaper; + + PrinterInfoManager( Type eType = Type::Default ); + + virtual void initialize(); + + // 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; + +public: + + // there can only be one + static PrinterInfoManager& get(); + // only called by SalData destructor, frees the global instance + static void release(); + + // get PrinterInfoManager type + Type getType() const { return m_eType; } + + // lists the names of all known printers + void listPrinters( std::vector< OUString >& rVector ) const; + + // gets info about a named printer + const PrinterInfo& getPrinterInfo( const OUString& rPrinter ) const; + + // gets the name of the default printer + const OUString& getDefaultPrinter() const { return m_aDefaultPrinter; } + + virtual void setupJobContextData( JobData& rData ); + + // 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 ); + + // 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 OUString& rPrinterName, bool bQuickCommand ); + // close the FILE* returned by startSpool and does the actual spooling + // set bBanner to "false" will attempt to suppress banner printing + // set bBanner to "true" will rely on the system default + // returns true on success + virtual bool endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString &rFaxNumber ); + + 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 OUString& rPrinterName, const char* pToken ) const; + + virtual ~PrinterInfoManager(); +}; + +} // namespace + +#endif // INCLUDED_VCL_PRINTERINFOMANAGER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5AccessibleEventListener.hxx b/vcl/inc/qt5/Qt5AccessibleEventListener.hxx new file mode 100644 index 000000000..0fd3783ee --- /dev/null +++ b/vcl/inc/qt5/Qt5AccessibleEventListener.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include + +#include "Qt5AccessibleWidget.hxx" + +#include + +class Qt5AccessibleEventListener final + : public cppu::WeakImplHelper +{ +public: + Qt5AccessibleEventListener( + const css::uno::Reference xAccessible, + Qt5AccessibleWidget* pAccessibleWidget); + + virtual void SAL_CALL + notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) override; + + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + +private: + css::uno::Reference m_xAccessible; + Qt5AccessibleWidget* m_pAccessibleWidget; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5AccessibleWidget.hxx b/vcl/inc/qt5/Qt5AccessibleWidget.hxx new file mode 100644 index 000000000..aacaba9a8 --- /dev/null +++ b/vcl/inc/qt5/Qt5AccessibleWidget.hxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class Qt5Frame; +class Qt5Widget; + +class Qt5AccessibleWidget final : public QObject, + public QAccessibleInterface, + public QAccessibleActionInterface, + public QAccessibleTextInterface, + public QAccessibleEditableTextInterface, + public QAccessibleTableInterface, + public QAccessibleValueInterface +{ + Q_OBJECT + +public: + Qt5AccessibleWidget(const css::uno::Reference xAccessible, + QObject* pObject); + QWindow* window() const override; + int childCount() const override; + int indexOfChild(const QAccessibleInterface* child) const override; + QVector> + relations(QAccessible::Relation match = QAccessible::AllRelations) const override; + QAccessibleInterface* focusChild() const override; + + QRect rect() const override; + + QAccessibleInterface* parent() const override; + QAccessibleInterface* child(int index) const override; + + QString text(QAccessible::Text t) const override; + QAccessible::Role role() const override; + QAccessible::State state() const override; + + QColor foregroundColor() const override; + QColor backgroundColor() const override; + + bool isValid() const override; + QObject* object() const override; + void setText(QAccessible::Text t, const QString& text) override; + QAccessibleInterface* childAt(int x, int y) const override; + + void* interface_cast(QAccessible::InterfaceType t) override; + + // QAccessibleActionInterface + QStringList actionNames() const override; + void doAction(const QString& actionName) override; + QStringList keyBindingsForAction(const QString& actionName) const override; + + static QAccessibleValueInterface* valueInterface(); + static QAccessibleTextInterface* textInterface(); + + // QAccessibleTextInterface + void addSelection(int startOffset, int endOffset) override; + QString attributes(int offset, int* startOffset, int* endOffset) const override; + int characterCount() const override; + QRect characterRect(int offset) const override; + int cursorPosition() const override; + int offsetAtPoint(const QPoint& point) const override; + void removeSelection(int selectionIndex) override; + void scrollToSubstring(int startIndex, int endIndex) override; + void selection(int selectionIndex, int* startOffset, int* endOffset) const override; + int selectionCount() const override; + void setCursorPosition(int position) override; + void setSelection(int selectionIndex, int startOffset, int endOffset) override; + QString text(int startOffset, int endOffset) const override; + QString textAfterOffset(int offset, QAccessible::TextBoundaryType boundaryType, + int* startOffset, int* endOffset) const override; + QString textAtOffset(int offset, QAccessible::TextBoundaryType boundaryType, int* startOffset, + int* endOffset) const override; + QString textBeforeOffset(int offset, QAccessible::TextBoundaryType boundaryType, + int* startOffset, int* endOffset) const override; + + // QAccessibleEditableTextInterface + virtual void deleteText(int startOffset, int endOffset) override; + virtual void insertText(int offset, const QString& text) override; + virtual void replaceText(int startOffset, int endOffset, const QString& text) override; + + // QAccessibleValueInterface + QVariant currentValue() const override; + QVariant maximumValue() const override; + QVariant minimumStepSize() const override; + QVariant minimumValue() const override; + void setCurrentValue(const QVariant& value) override; + + // QAccessibleTableInterface + virtual QAccessibleInterface* caption() const override; + virtual QAccessibleInterface* cellAt(int row, int column) const override; + virtual int columnCount() const override; + virtual QString columnDescription(int column) const override; + virtual bool isColumnSelected(int column) const override; + virtual bool isRowSelected(int row) const override; + virtual void modelChange(QAccessibleTableModelChangeEvent* event) override; + virtual int rowCount() const override; + virtual QString rowDescription(int row) const override; + virtual bool selectColumn(int column) override; + virtual bool selectRow(int row) override; + virtual int selectedCellCount() const override; + virtual QList selectedCells() const override; + virtual int selectedColumnCount() const override; + virtual QList selectedColumns() const override; + virtual int selectedRowCount() const override; + virtual QList selectedRows() const override; + virtual QAccessibleInterface* summary() const override; + virtual bool unselectColumn(int column) override; + virtual bool unselectRow(int row) override; + + // Factory + static QAccessibleInterface* customFactory(const QString& classname, QObject* object); + +private: + css::uno::Reference m_xAccessible; + css::uno::Reference getAccessibleContextImpl() const; + QObject* m_pObject; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Bitmap.hxx b/vcl/inc/qt5/Qt5Bitmap.hxx new file mode 100644 index 000000000..8ff4297e4 --- /dev/null +++ b/vcl/inc/qt5/Qt5Bitmap.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +class QImage; + +class Qt5Bitmap final : public SalBitmap +{ + std::unique_ptr m_pImage; + BitmapPalette m_aPalette; + + // for 4bit support + std::unique_ptr m_pBuffer; + Size m_aSize; + sal_uInt32 m_nScanline; + +public: + Qt5Bitmap(); + Qt5Bitmap(const QImage& rQImage); + + const QImage* GetQImage() const { return m_pImage.get(); } + + virtual bool Create(const Size& rSize, sal_uInt16 nBitCount, + const BitmapPalette& rPal) override; + virtual bool Create(const SalBitmap& rSalBmp) override; + virtual bool Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) override; + virtual bool Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount) override; + virtual bool Create(const css::uno::Reference& rBitmapCanvas, + Size& rSize, bool bMask = false) override; + virtual void Destroy() final override; + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override; + virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override; + virtual bool GetSystemData(BitmapSystemData& rData) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale(const double& rScaleX, const double& rScaleY, + BmpScaleFlag nScaleFlag) override; + virtual bool Replace(const Color& rSearchColor, const Color& rReplaceColor, + sal_uInt8 nTol) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Clipboard.hxx b/vcl/inc/qt5/Qt5Clipboard.hxx new file mode 100644 index 000000000..b99534f59 --- /dev/null +++ b/vcl/inc/qt5/Qt5Clipboard.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + * This implementation has two main functions, which handle the clipboard content: + * the XClipboard::setContent function and the QClipboard::change signal handler. + * + * The first just sets the respective clipboard to the expected content from LO, + * the latter will handle any reported changes. + **/ +class Qt5Clipboard final + : public QObject, + public cppu::WeakComponentImplHelper +{ + Q_OBJECT + + osl::Mutex m_aMutex; + const OUString m_aClipboardName; + const QClipboard::Mode m_aClipboardMode; + // has to be set, if LO changes the QClipboard itself, so it won't instantly lose + // ownership by it's self-triggered QClipboard::changed handler + bool m_bOwnClipboardChange; + // true, if LO really wants to give up clipboard ownership + bool m_bDoClear; + + // if not empty, this holds the setContents provided XTransferable or a Qt5ClipboardTransferable + css::uno::Reference m_aContents; + // the owner of the current contents, which must be informed on content change + css::uno::Reference m_aOwner; + std::vector> m_aListeners; + + static bool isOwner(const QClipboard::Mode aMode); + static bool isSupported(const QClipboard::Mode aMode); + + explicit Qt5Clipboard(const OUString& aModeString, const QClipboard::Mode aMode); + +private Q_SLOTS: + void handleChanged(QClipboard::Mode mode); + void handleClearClipboard(); + +signals: + void clearClipboard(); + +public: + // factory function to construct only valid Qt5Clipboard objects by name + static css::uno::Reference create(const OUString& aModeString); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XClipboard + virtual css::uno::Reference SAL_CALL getContents() override; + virtual void SAL_CALL setContents( + const css::uno::Reference& xTrans, + const css::uno::Reference& xClipboardOwner) + override; + virtual OUString SAL_CALL getName() override; + + // XClipboardEx + virtual sal_Int8 SAL_CALL getRenderingCapabilities() override; + + // XFlushableClipboard + virtual void SAL_CALL flushClipboard() override; + + // XClipboardNotifier + virtual void SAL_CALL addClipboardListener( + const css::uno::Reference& listener) + override; + virtual void SAL_CALL removeClipboardListener( + const css::uno::Reference& listener) + override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Data.hxx b/vcl/inc/qt5/Qt5Data.hxx new file mode 100644 index 000000000..1834835d3 --- /dev/null +++ b/vcl/inc/qt5/Qt5Data.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include +#include +#include + +class QCursor; + +class VCLPLUG_QT5_PUBLIC Qt5Data final : public GenericUnixSalData +{ + o3tl::enumarray> m_aCursors; + +public: + explicit Qt5Data(SalInstance* pInstance); + virtual ~Qt5Data() override; + + virtual void ErrorTrapPush() override; + virtual bool ErrorTrapPop(bool bIgnoreError = true) override; + + QCursor& getCursor(PointerStyle ePointerStyle); + + static bool noNativeControls(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5DragAndDrop.hxx b/vcl/inc/qt5/Qt5DragAndDrop.hxx new file mode 100644 index 000000000..c88465ab3 --- /dev/null +++ b/vcl/inc/qt5/Qt5DragAndDrop.hxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include +#include +#include +#include + +class Qt5Frame; + +class Qt5DragSource final + : public cppu::WeakComponentImplHelper +{ + osl::Mutex m_aMutex; + Qt5Frame* m_pFrame; + css::uno::Reference m_xListener; + +public: + Qt5DragSource() + : WeakComponentImplHelper(m_aMutex) + , m_pFrame(nullptr) + { + } + + virtual ~Qt5DragSource() override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported() override; + virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) override; + virtual void SAL_CALL startDrag( + const css::datatransfer::dnd::DragGestureEvent& trigger, sal_Int8 sourceActions, + sal_Int32 cursor, sal_Int32 image, + const css::uno::Reference& transferable, + const css::uno::Reference& listener) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArguments) override; + void deinitialize(); + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + void fire_dragEnd(sal_Int8 nAction, bool bSuccessful); +}; + +class Qt5DropTarget final + : public cppu::WeakComponentImplHelper +{ + osl::Mutex m_aMutex; + Qt5Frame* m_pFrame; + sal_Int8 m_nDropAction; + bool m_bActive; + sal_Int8 m_nDefaultActions; + std::vector> m_aListeners; + bool m_bDropSuccessful; + +public: + Qt5DropTarget(); + virtual ~Qt5DropTarget() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArgs) override; + void deinitialize(); + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( + const css::uno::Reference&) override; + virtual void SAL_CALL removeDropTargetListener( + const css::uno::Reference&) override; + virtual sal_Bool SAL_CALL isActive() override; + virtual void SAL_CALL setActive(sal_Bool active) override; + virtual sal_Int8 SAL_CALL getDefaultActions() override; + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override; + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) override; + virtual void SAL_CALL rejectDrag() override; + + // XDropTargetDropContext + virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) override; + virtual void SAL_CALL rejectDrop() override; + virtual void SAL_CALL dropComplete(sal_Bool success) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); + void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte); + void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde); + void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde); + + sal_Int8 proposedDropAction() const { return m_nDropAction; } + bool dropSuccessful() const { return m_bDropSuccessful; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5FilePicker.hxx b/vcl/inc/qt5/Qt5FilePicker.hxx new file mode 100644 index 000000000..5fef2aaea --- /dev/null +++ b/vcl/inc/qt5/Qt5FilePicker.hxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +class QComboBox; +class QGridLayout; +class QLabel; +class QWidget; + +typedef ::cppu::WeakComponentImplHelper + Qt5FilePicker_Base; + +class VCLPLUG_QT5_PUBLIC Qt5FilePicker : public QObject, public Qt5FilePicker_Base +{ + Q_OBJECT + +private: + css::uno::Reference m_context; + + css::uno::Reference m_xListener; + + osl::Mutex m_aHelperMutex; ///< mutex used by the WeakComponentImplHelper + + QStringList m_aNamedFilterList; ///< to keep the original sequence + QHash m_aTitleToFilterMap; + // to retrieve the filename extension for a given filter + QHash m_aNamedFilterToExtensionMap; + QString m_aCurrentFilter; + + QGridLayout* m_pLayout; ///< layout for extra custom controls + QHash m_aCustomWidgetsMap; ///< map of SAL control ID's to widget + + const bool m_bIsFolderPicker; + + QWidget* m_pParentWidget; + +protected: + std::unique_ptr m_pFileDialog; ///< the file picker dialog + QWidget* m_pExtraControls; ///< widget to contain extra custom controls + +public: + // use non-native file dialog by default; there's no easy way to add custom widgets + // in a generic way in the native one + explicit Qt5FilePicker(css::uno::Reference const& context, + QFileDialog::FileMode, bool bUseNative = false); + virtual ~Qt5FilePicker() override; + + // XFilePickerNotifier + virtual void SAL_CALL addFilePickerListener( + const css::uno::Reference& xListener) override; + virtual void SAL_CALL removeFilePickerListener( + const css::uno::Reference& xListener) override; + + // XFilterManager functions + virtual void SAL_CALL appendFilter(const OUString& rTitle, const OUString& rFilter) override; + virtual void SAL_CALL setCurrentFilter(const OUString& rTitle) override; + virtual OUString SAL_CALL getCurrentFilter() override; + + // XFilterGroupManager functions + virtual void SAL_CALL + appendFilterGroup(const OUString& rGroupTitle, + const css::uno::Sequence& rFilters) override; + + // XCancellable + virtual void SAL_CALL cancel() override; + + // XExecutableDialog functions + virtual void SAL_CALL setTitle(const OUString& rTitle) override; + virtual sal_Int16 SAL_CALL execute() override; + + // XFilePicker functions + virtual void SAL_CALL setMultiSelectionMode(sal_Bool bMode) override; + virtual void SAL_CALL setDefaultName(const OUString& rName) override; + virtual void SAL_CALL setDisplayDirectory(const OUString& rDirectory) override; + virtual OUString SAL_CALL getDisplayDirectory() override; + virtual css::uno::Sequence SAL_CALL getFiles() override; + + // XFilePickerControlAccess functions + virtual void SAL_CALL setValue(sal_Int16 nControlId, sal_Int16 nControlAction, + const css::uno::Any& rValue) override; + virtual css::uno::Any SAL_CALL getValue(sal_Int16 nControlId, + sal_Int16 nControlAction) override; + virtual void SAL_CALL enableControl(sal_Int16 nControlId, sal_Bool bEnable) override; + virtual void SAL_CALL setLabel(sal_Int16 nControlId, const OUString& rLabel) override; + virtual OUString SAL_CALL getLabel(sal_Int16 nControlId) override; + + // XFilePicker2 functions + virtual css::uno::Sequence SAL_CALL getSelectedFiles() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArguments) override; + + // XEventListener + void SAL_CALL disposing(const css::lang::EventObject& rEvent) override; + using cppu::WeakComponentImplHelperBase::disposing; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XFolderPicker functions + virtual OUString SAL_CALL getDirectory() override; + virtual void SAL_CALL setDescription(const OUString& rDescription) override; + + // XTerminateListener + void SAL_CALL queryTermination(const css::lang::EventObject& aEvent) override; + void SAL_CALL notifyTermination(const css::lang::EventObject& aEvent) override; + +protected: + virtual void addCustomControl(sal_Int16 controlId); + void setCustomControlWidgetLayout(QGridLayout* pLayout) { m_pLayout = pLayout; } + +private: + Qt5FilePicker(const Qt5FilePicker&) = delete; + Qt5FilePicker& operator=(const Qt5FilePicker&) = delete; + + static QString getResString(const char* pRedId); + static css::uno::Any handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction); + static void handleSetListValue(QComboBox* pQComboBox, sal_Int16 nAction, + const css::uno::Any& rValue); + +private Q_SLOTS: + // emit XFilePickerListener controlStateChanged event + void filterSelected(const QString&); + // emit XFilePickerListener fileSelectionChanged event + void currentChanged(const QString&); + // (un)set automatic file extension + virtual void updateAutomaticFileExtension(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Font.hxx b/vcl/inc/qt5/Qt5Font.hxx new file mode 100644 index 000000000..0720be931 --- /dev/null +++ b/vcl/inc/qt5/Qt5Font.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include "Qt5FontFace.hxx" + +class Qt5Font final : public QFont, public LogicalFontInstance +{ + friend rtl::Reference + Qt5FontFace::CreateFontInstance(const FontSelectPattern&) const; + + bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; + bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; + + virtual hb_font_t* ImplInitHbFont() override; + + explicit Qt5Font(const PhysicalFontFace&, const FontSelectPattern&); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5FontFace.hxx b/vcl/inc/qt5/Qt5FontFace.hxx new file mode 100644 index 000000000..585f4aaa8 --- /dev/null +++ b/vcl/inc/qt5/Qt5FontFace.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#include +#include + +class FontAttributes; +class FontSelectPattern; + +class Qt5FontFace final : public PhysicalFontFace +{ +public: + static Qt5FontFace* fromQFont(const QFont& rFont); + static Qt5FontFace* fromQFontDatabase(const QString& aFamily, const QString& aStyle); + static void fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA); + + VCLPLUG_QT5_PUBLIC static FontWeight toFontWeight(const int nWeight); + VCLPLUG_QT5_PUBLIC static FontWidth toFontWidth(const int nStretch); + VCLPLUG_QT5_PUBLIC static FontItalic toFontItalic(const QFont::Style eStyle); + + sal_IntPtr GetFontId() const override; + + int GetFontTable(const char pTagName[5], unsigned char*) const; + + const FontCharMapRef& GetFontCharMap() const; + bool GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const; + bool HasChar(sal_uInt32 cChar) const; + + rtl::Reference + CreateFontInstance(const FontSelectPattern& rFSD) const override; + +private: + Qt5FontFace(const Qt5FontFace&); + Qt5FontFace(const FontAttributes& rFA, const QString& rFontID); + + const QString m_aFontId; + mutable FontCharMapRef m_xCharMap; + mutable vcl::FontCapabilities m_aFontCapabilities; + mutable bool m_bFontCapabilitiesRead; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Frame.hxx b/vcl/inc/qt5/Qt5Frame.hxx new file mode 100644 index 000000000..0caf1bc3e --- /dev/null +++ b/vcl/inc/qt5/Qt5Frame.hxx @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include "Qt5Tools.hxx" + +#include +#include +#include + +#include + +#if QT5_USING_X11 +#include +// any better way to get rid of the X11 / Qt type clashes? +#undef Bool +#undef CursorShape +#undef Expose +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef FontChange +#undef None +#undef Status +#undef Unsorted +#endif + +class Qt5DragSource; +class Qt5DropTarget; +class Qt5Graphics; +class Qt5Instance; +class Qt5MainWindow; +class Qt5Menu; +class Qt5SvpGraphics; + +class QDragMoveEvent; +class QDropEvent; +class QImage; +class QMimeData; +class QPaintDevice; +class QScreen; +class QWidget; + +class VCLPLUG_QT5_PUBLIC Qt5Frame : public QObject, public SalFrame +{ + Q_OBJECT + + friend class Qt5Widget; + + QWidget* m_pQWidget; + Qt5MainWindow* m_pTopLevel; + + const bool m_bUseCairo; + std::unique_ptr m_pQImage; + std::unique_ptr m_pQt5Graphics; + UniqueCairoSurface m_pSurface; + std::unique_ptr m_pOurSvpGraphics; + // in base class, this ptr is the same as m_pOurSvpGraphic + // in derived class, it can point to a derivative + // of Qt5SvpGraphics (which the derived class then owns) + Qt5SvpGraphics* m_pSvpGraphics; + DamageHandler m_aDamageHandler; + QRegion m_aRegion; + bool m_bNullRegion; + + bool m_bGraphicsInUse; + bool m_bGraphicsInvalid; + SalFrameStyleFlags m_nStyle; + Qt5Frame* m_pParent; + PointerStyle m_ePointerStyle; + + SystemEnvData m_aSystemData; + + Qt5Menu* m_pSalMenu; + + Qt5DragSource* m_pDragSource; + Qt5DropTarget* m_pDropTarget; + bool m_bInDrag; + + bool m_bDefaultSize; + bool m_bDefaultPos; + bool m_bFullScreen; + bool m_bFullScreenSpanAll; + sal_uInt32 m_nRestoreScreen; + QRect m_aRestoreGeometry; + +#if QT5_USING_X11 + ScreenSaverInhibitor m_ScreenSaverInhibitor; +#endif + + void SetDefaultPos(); + Size CalcDefaultSize(); + void SetDefaultSize(); + + bool isChild(bool bPlug = true, bool bSysChild = true) const + { + SalFrameStyleFlags nMask = SalFrameStyleFlags::NONE; + if (bPlug) + nMask |= SalFrameStyleFlags::PLUG; + if (bSysChild) + nMask |= SalFrameStyleFlags::SYSTEMCHILD; + return bool(m_nStyle & nMask); + } + + bool isWindow() const; + QWindow* windowHandle() const; + QScreen* screen() const; + bool isMinimized() const; + bool isMaximized() const; + void SetWindowStateImpl(Qt::WindowStates eState); + + void fixICCCMwindowGroup(); + +public: + Qt5Frame(Qt5Frame* pParent, SalFrameStyleFlags nSalFrameStyle, bool bUseCairo); + virtual ~Qt5Frame() override; + + QWidget* GetQWidget() const { return m_pQWidget; } + Qt5MainWindow* GetTopLevelWindow() const { return m_pTopLevel; } + QWidget* asChild() const; + qreal devicePixelRatioF() const; + + void Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, + sal_Int32 nExtentsHeight) const; + + void InitQt5SvpGraphics(Qt5SvpGraphics* pQt5SvpGraphics); + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + virtual bool PostEvent(std::unique_ptr pData) override; + + virtual void SetTitle(const OUString& rTitle) override; + virtual void SetIcon(sal_uInt16 nIcon) override; + virtual void SetMenu(SalMenu* pMenu) override; + virtual void DrawMenuBar() override; + + virtual void registerDragSource(Qt5DragSource* pDragSource); + virtual void deregisterDragSource(Qt5DragSource const* pDragSource); + virtual void registerDropTarget(Qt5DropTarget* pDropTarget); + virtual void deregisterDropTarget(Qt5DropTarget const* pDropTarget); + + void handleDragLeave(); + void handleDragMove(QDragMoveEvent* pEvent); + void handleDrop(QDropEvent* pEvent); + + virtual void SetExtendedFrameStyle(SalExtStyle nExtStyle) override; + virtual void Show(bool bVisible, bool bNoActivate = false) override; + virtual void SetMinClientSize(long nWidth, long nHeight) override; + virtual void SetMaxClientSize(long nWidth, long nHeight) override; + virtual void SetPosSize(long nX, long nY, long nWidth, long nHeight, + sal_uInt16 nFlags) override; + virtual void GetClientSize(long& rWidth, long& rHeight) override; + virtual void GetWorkArea(tools::Rectangle& rRect) override; + virtual SalFrame* GetParent() const override; + virtual void SetModal(bool bModal) override; + virtual bool GetModal() const override; + virtual void SetWindowState(const SalFrameState* pState) override; + virtual bool GetWindowState(SalFrameState* pState) override; + virtual void ShowFullScreen(bool bFullScreen, sal_Int32 nDisplay) override; + virtual void StartPresentation(bool bStart) override; + virtual void SetAlwaysOnTop(bool bOnTop) override; + virtual void ToTop(SalFrameToTop nFlags) override; + virtual void SetPointer(PointerStyle ePointerStyle) override; + virtual void CaptureMouse(bool bMouse) override; + virtual void SetPointerPos(long nX, long nY) override; + virtual bool ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) override; + using SalFrame::Flush; + virtual void Flush() override; + virtual void SetInputContext(SalInputContext* pContext) override; + virtual void EndExtTextInput(EndExtTextInputFlags nFlags) override; + virtual OUString GetKeyName(sal_uInt16 nKeyCode) override; + virtual bool MapUnicodeToKeyCode(sal_Unicode aUnicode, LanguageType aLangType, + vcl::KeyCode& rKeyCode) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings(AllSettings& rSettings) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress(sal_uInt16 nKeyCode) override; + virtual void SetParent(SalFrame* pNewParent) override; + virtual bool SetPluginParent(SystemParentData* pNewParent) override; + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion(sal_uInt32 nRects) override; + virtual void UnionClipRegion(long nX, long nY, long nWidth, long nHeight) override; + virtual void EndSetClipRegion() override; + + virtual void SetScreenNumber(unsigned int) override; + virtual void SetApplicationID(const OUString&) override; + + inline bool CallCallback(SalEvent nEvent, const void* pEvent) const; + + cairo_t* getCairoContext() const; +}; + +inline bool Qt5Frame::CallCallback(SalEvent nEvent, const void* pEvent) const +{ + SolarMutexGuard aGuard; + return SalFrame::CallCallback(nEvent, pEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx new file mode 100644 index 000000000..bc4870ee7 --- /dev/null +++ b/vcl/inc/qt5/Qt5Graphics.hxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +#include "Qt5GraphicsBase.hxx" + +class PhysicalFontCollection; +class QImage; +class QPushButton; +class Qt5Font; +class Qt5FontFace; +class Qt5Frame; +class Qt5Painter; + +class Qt5Graphics final : public SalGraphics, public Qt5GraphicsBase +{ + friend class Qt5Bitmap; + friend class Qt5Painter; + + Qt5Frame* m_pFrame; + QImage* m_pQImage; + QRegion m_aClipRegion; + QPainterPath m_aClipPath; + Color m_aLineColor; + Color m_aFillColor; + QPainter::CompositionMode m_eCompositionMode; + + PhysicalFontCollection* m_pFontCollection; + rtl::Reference m_pTextStyle[MAX_FALLBACK]; + Color m_aTextColor; + std::unique_ptr m_focusedButton; + std::unique_ptr m_image; + QRect m_lastPopupRect; + + Qt5Graphics(Qt5Frame* pFrame, QImage* pQImage); + + void drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage); + + void handleDamage(const tools::Rectangle&) override; + +public: + Qt5Graphics(Qt5Frame* pFrame) + : Qt5Graphics(pFrame, nullptr) + { + } + Qt5Graphics(QImage* pQImage) + : Qt5Graphics(nullptr, pQImage) + { + } + virtual ~Qt5Graphics() override; + + void ChangeQImage(QImage* pImage); + + virtual SalGraphicsImpl* GetImpl() const override; + virtual SystemGraphicsData GetGraphicsData() const override; + virtual bool supportsOperation(OutDevSupportType) const override; + virtual OUString getRenderBackendName() const override { return "qt5"; } + +#if ENABLE_CAIRO_CANVAS + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr + CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, + int width, int height) const override; + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, + const BitmapSystemData& rData, + const Size& rSize) const override; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, + const basegfx::B2ISize& rSize) const override; + virtual SystemFontData GetSysFontData(int nFallbacklevel) const override; +#endif // ENABLE_CAIRO_CANVAS + + // GDI + + virtual bool setClipRegion(const vcl::Region&) override; + virtual void ResetClipRegion() override; + + virtual void drawPixel(long nX, long nY) override; + virtual void drawPixel(long nX, long nY, Color nColor) override; + virtual void drawLine(long nX1, long nY1, long nX2, long nY2) override; + virtual void drawRect(long nX, long nY, long nWidth, long nHeight) override; + virtual void drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) override; + virtual void drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) override; + virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry) override; + virtual bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, double fTransparency) override; + virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, + const PolyFlags* pFlgAry) override; + virtual bool drawPolygonBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, + const PolyFlags* pFlgAry) override; + virtual bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry) override; + virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, double fTransparency, double fLineWidths, + const std::vector* pStroke, // MM01 + basegfx::B2DLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline) override; + virtual bool drawGradient(const tools::PolyPolygon&, const Gradient&) override; + + virtual void copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool bWindowInvalidate) override; + + virtual void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override; + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override; + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap) override; + virtual void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + Color nMaskColor) override; + + virtual std::shared_ptr getBitmap(long nX, long nY, long nWidth, + long nHeight) override; + virtual Color getPixel(long nX, long nY) override; + + virtual void invert(long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) override; + virtual void invert(sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags) override; + + virtual bool drawEPS(long nX, long nY, long nWidth, long nHeight, void* pPtr, + sal_uInt32 nSize) override; + + virtual bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override; + + virtual bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap) override; + + virtual bool drawAlphaBitmap(const SalTwoRect&, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) override; + + bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + + virtual bool drawAlphaRect(long nX, long nY, long nWidth, long nHeight, + sal_uInt8 nTransparency) override; + + virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; + virtual sal_uInt16 GetBitCount() const override; + virtual long GetGraphicsWidth() const override; + + virtual void SetLineColor() override; + virtual void SetLineColor(Color nColor) override; + virtual void SetFillColor() override; + virtual void SetFillColor(Color nColor) override; + virtual void SetXORMode(bool bSet, bool bInvertOnly) override; + virtual void SetROPLineColor(SalROPColor nROPColor) override; + virtual void SetROPFillColor(SalROPColor nROPColor) override; + + // Text rendering + font support + + virtual void SetTextColor(Color nColor) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric(ImplFontMetricDataRef&, int nFallbackLevel) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const override; + virtual void GetDevFontList(PhysicalFontCollection*) override; + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont(PhysicalFontCollection*, const OUString& rFileURL, + const OUString& rFontName) override; + virtual bool CreateFontSubset(const OUString& rToFile, const PhysicalFontFace* pFont, + const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, + sal_Int32* pWidths, int nGlyphs, + FontSubsetInfo& rInfo // out parameter + ) override; + + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + virtual void FreeEmbedFontData(const void* pData, long nDataLen) override; + + virtual void GetGlyphWidths(const PhysicalFontFace*, bool bVertical, + std::vector& rWidths, Ucs2UIntMap& rUnicodeEnc) override; + + virtual std::unique_ptr GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout(const GenericSalLayout&) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5GraphicsBase.hxx b/vcl/inc/qt5/Qt5GraphicsBase.hxx new file mode 100644 index 000000000..ef7955186 --- /dev/null +++ b/vcl/inc/qt5/Qt5GraphicsBase.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +class Qt5GraphicsBase +{ + qreal m_fDPR; + +protected: + Qt5GraphicsBase() + : m_fDPR(qApp ? qApp->devicePixelRatio() : 1.0) + { + } + + void setDevicePixelRatioF(qreal fDPR) { m_fDPR = fDPR; } + +public: + qreal devicePixelRatioF() const { return m_fDPR; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Graphics_Controls.hxx b/vcl/inc/qt5/Qt5Graphics_Controls.hxx new file mode 100644 index 000000000..325e5c351 --- /dev/null +++ b/vcl/inc/qt5/Qt5Graphics_Controls.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +class Qt5GraphicsBase; + +class Qt5Graphics_Controls final : public vcl::WidgetDrawInterface +{ + std::unique_ptr m_image; + QRect m_lastPopupRect; + Qt5GraphicsBase const& m_rGraphics; + +public: + Qt5Graphics_Controls(const Qt5GraphicsBase& rGraphics); + + QImage* getImage() { return m_image.get(); } + + bool isNativeControlSupported(ControlType nType, ControlPart nPart) override; + bool hitTestNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, const Point& aPos, + bool& rIsInside) override; + bool drawNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + const Color& rBackgroundColor) override; + bool getNativeControlRegion(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle& rNativeBoundingRegion, + tools::Rectangle& rNativeContentRegion) override; + +private: + static int pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option = nullptr); + static QSize sizeFromContents(QStyle::ContentsType type, const QStyleOption* option, + const QSize& contentsSize); + static QRect subControlRect(QStyle::ComplexControl control, const QStyleOptionComplex* option, + QStyle::SubControl subControl); + static QRect subElementRect(QStyle::SubElement element, const QStyleOption* option); + + void draw(QStyle::ControlElement element, QStyleOption* option, QImage* image, + QStyle::State const state = QStyle::State_None, QRect rect = QRect()); + void draw(QStyle::PrimitiveElement element, QStyleOption* option, QImage* image, + QStyle::State const state = QStyle::State_None, QRect rect = QRect()); + void draw(QStyle::ComplexControl element, QStyleOptionComplex* option, QImage* image, + QStyle::State const state = QStyle::State_None); + void drawFrame(QStyle::PrimitiveElement element, QImage* image, QStyle::State const& state, + bool bClip = true, + QStyle::PixelMetric eLineMetric = QStyle::PM_DefaultFrameWidth); + + static void fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot); + void fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, bool bDownscale); + + enum class Round + { + Floor, + Ceil, + }; + + int downscale(int value, Round eRound); + int upscale(int value, Round eRound); + QRect downscale(const QRect& rect); + QRect upscale(const QRect& rect); + QSize downscale(const QSize& size, Round eRound); + QSize upscale(const QSize& size, Round eRound); + QPoint upscale(const QPoint& point, Round eRound); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Instance.hxx b/vcl/inc/qt5/Qt5Instance.hxx new file mode 100644 index 000000000..361eca0fc --- /dev/null +++ b/vcl/inc/qt5/Qt5Instance.hxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "Qt5FilePicker.hxx" + +class QApplication; +class SalYieldMutex; +class SalFrame; + +struct StdFreeCStr +{ + void operator()(char* arg) const noexcept { std::free(arg); } +}; +using FreeableCStr = std::unique_ptr; + +class VCLPLUG_QT5_PUBLIC Qt5Instance : public QObject, + public SalGenericInstance, + public SalUserEventList +{ + Q_OBJECT + + osl::Condition m_aWaitingYieldCond; + int m_postUserEventId; + const bool m_bUseCairo; + std::unordered_map> m_aClipboards; + + std::unique_ptr m_pQApplication; + std::vector m_pFakeArgvFreeable; + std::unique_ptr m_pFakeArgv; + std::unique_ptr m_pFakeArgc; + + Timer m_aUpdateStyleTimer; + bool m_bUpdateFonts; + + DECL_LINK(updateStyleHdl, Timer*, void); + void AfterAppInit() override; + +private Q_SLOTS: + bool ImplYield(bool bWait, bool bHandleAllCurrentEvents); + void ImplRunInMain(); + static void deleteObjectLater(QObject* pObject); + +Q_SIGNALS: + bool ImplYieldSignal(bool bWait, bool bHandleAllCurrentEvents); + void ImplRunInMainSignal(); + void deleteObjectLaterSignal(QObject* pObject); + +protected: + virtual Qt5FilePicker* + createPicker(css::uno::Reference const& context, + QFileDialog::FileMode); + +public: + explicit Qt5Instance(std::unique_ptr& pQApp, bool bUseCairo = false); + virtual ~Qt5Instance() override; + + // handle common SalInstance setup + static void AllocFakeCmdlineArgs(std::unique_ptr& rFakeArgv, + std::unique_ptr& rFakeArgc, + std::vector& rFakeArgvFreeable); + void MoveFakeCmdlineArgs(std::unique_ptr& rFakeArgv, std::unique_ptr& rFakeArgc, + std::vector& rFakeArgvFreeable); + static std::unique_ptr CreateQApplication(int& nArgc, char** pArgv); + + void RunInMainThread(std::function func); + + virtual SalFrame* CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) override; + virtual SalFrame* CreateChildFrame(SystemParentData* pParent, + SalFrameStyleFlags nStyle) override; + virtual void DestroyFrame(SalFrame* pFrame) override; + + virtual SalObject* CreateObject(SalFrame* pParent, SystemWindowData* pWindowData, + bool bShow) override; + virtual void DestroyObject(SalObject* pObject) override; + + virtual std::unique_ptr + CreateVirtualDevice(SalGraphics* pGraphics, long& nDX, long& nDY, DeviceFormat eFormat, + const SystemGraphicsData* pData = nullptr) override; + + virtual SalInfoPrinter* CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData) override; + virtual void DestroyInfoPrinter(SalInfoPrinter* pPrinter) override; + virtual std::unique_ptr CreatePrinter(SalInfoPrinter* pInfoPrinter) override; + virtual void GetPrinterQueueInfo(ImplPrnQueueList* pList) override; + virtual void GetPrinterQueueState(SalPrinterQueueInfo* pInfo) override; + virtual OUString GetDefaultPrinter() override; + virtual void PostPrintersChanged() override; + + virtual std::unique_ptr CreateMenu(bool, Menu*) override; + virtual std::unique_ptr CreateMenuItem(const SalItemParams&) override; + + virtual SalTimer* CreateSalTimer() override; + virtual SalSystem* CreateSalSystem() override; + virtual std::shared_ptr CreateSalBitmap() override; + + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput(VclInputFlags nType) override; + + virtual OpenGLContext* CreateOpenGLContext() override; + + virtual OUString GetConnectionIdentifier() override; + + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, + const OUString& rDocumentService) override; + + virtual std::unique_ptr CreatePrintGraphics() override; + + virtual bool IsMainThread() const override; + + virtual void TriggerUserEventProcessing() override; + virtual void ProcessEvent(SalUserEvent aEvent) override; + + bool hasNativeFileSelection() const override { return true; } + css::uno::Reference + createFilePicker(const css::uno::Reference&) override; + css::uno::Reference + createFolderPicker(const css::uno::Reference&) override; + + virtual css::uno::Reference + CreateClipboard(const css::uno::Sequence& i_rArguments) override; + virtual css::uno::Reference CreateDragSource() override; + virtual css::uno::Reference CreateDropTarget() override; + + void UpdateStyle(bool bFontsChanged); + + void* CreateGStreamerSink(const SystemChildWindow*) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5MainWindow.hxx b/vcl/inc/qt5/Qt5MainWindow.hxx new file mode 100644 index 000000000..f1e91b489 --- /dev/null +++ b/vcl/inc/qt5/Qt5MainWindow.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include "Qt5Frame.hxx" + +class Qt5MainWindow : public QMainWindow +{ + Q_OBJECT + + Qt5Frame& m_rFrame; + + virtual void closeEvent(QCloseEvent* pEvent) override; + void moveEvent(QMoveEvent*) override; + +public: + Qt5MainWindow(Qt5Frame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Menu.hxx b/vcl/inc/qt5/Qt5Menu.hxx new file mode 100644 index 000000000..2e5434f4d --- /dev/null +++ b/vcl/inc/qt5/Qt5Menu.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include + +#include + +class MenuItemList; +class QAction; +class QActionGroup; +class QPushButton; +class QMenu; +class QMenuBar; +class Qt5MenuItem; +class Qt5Frame; + +/* + * Qt5Menu can represent + * (1) the top-level menu of a menubar, in which case 'mbMenuBar' is true and + * 'mpQMenuBar' refers to the corresponding QMenuBar + * (2) another kind of menu (like a PopupMenu), in which case the corresponding QMenu + * object is instantiated and owned by this Qt5Menu (held in 'mpOwnedQMenu'). + * (3) a "submenu" in an existing menu (like (1)), in which case the corresponding + * QMenu object is owned by the corresponding Qt5MenuItem. + * + * For (2) and (3), member 'mpQMenu' points to the corresponding QMenu object. + */ +class Qt5Menu : public QObject, public SalMenu +{ + Q_OBJECT +private: + std::vector maItems; + VclPtr mpVCLMenu; + Qt5Menu* mpParentSalMenu; + Qt5Frame* mpFrame; + bool mbMenuBar; + QMenuBar* mpQMenuBar; + // self-created QMenu that this Qt5Menu represents, if applicable (s. comment for class) + std::unique_ptr mpOwnedQMenu; + // pointer to QMenu owned by the corresponding Qt5MenuItem or self (-> mpOwnedQMenu) + QMenu* mpQMenu; + QPushButton* mpCloseButton; + QMetaObject::Connection maCloseButtonConnection; + + void DoFullMenuUpdate(Menu* pMenuBar); + static void NativeItemText(OUString& rItemText); + + void InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos); + + void ReinitializeActionGroup(unsigned nPos); + void ResetAllActionGroups(); + void UpdateActionGroupItem(const Qt5MenuItem* pSalMenuItem); + +public: + Qt5Menu(bool bMenuBar); + + virtual bool VisibleMenuBar() override; // must return TRUE to actually DISPLAY native menu bars + + virtual void InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) override; + virtual void RemoveItem(unsigned nPos) override; + virtual void SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) override; + virtual void SetFrame(const SalFrame* pFrame) override; + const Qt5Frame* GetFrame() const; + virtual void ShowMenuBar(bool bVisible) override; + virtual bool ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect, + FloatWinPopupFlags nFlags) override; + Qt5Menu* GetTopLevel(); + virtual void SetItemBits(unsigned nPos, MenuItemBits nBits) override; + virtual void CheckItem(unsigned nPos, bool bCheck) override; + virtual void EnableItem(unsigned nPos, bool bEnable) override; + virtual void ShowItem(unsigned nPos, bool bShow) override; + virtual void SetItemText(unsigned nPos, SalMenuItem* pSalMenuItem, + const OUString& rText) override; + virtual void SetItemImage(unsigned nPos, SalMenuItem* pSalMenuItem, + const Image& rImage) override; + virtual void SetAccelerator(unsigned nPos, SalMenuItem* pSalMenuItem, + const vcl::KeyCode& rKeyCode, const OUString& rKeyName) override; + virtual void GetSystemMenuData(SystemMenuData* pData) override; + virtual void ShowCloseButton(bool bShow) override; + + void SetMenu(Menu* pMenu) { mpVCLMenu = pMenu; } + Menu* GetMenu() { return mpVCLMenu; } + unsigned GetItemCount() const { return maItems.size(); } + Qt5MenuItem* GetItemAtPos(unsigned nPos) { return maItems[nPos]; } + +private slots: + static void slotMenuTriggered(Qt5MenuItem* pQItem); + static void slotMenuAboutToShow(Qt5MenuItem* pQItem); + static void slotMenuAboutToHide(Qt5MenuItem* pQItem); + void slotCloseDocument(); +}; + +class Qt5MenuItem : public SalMenuItem +{ +public: + Qt5MenuItem(const SalItemParams*); + + QAction* getAction() const; + + Qt5Menu* mpParentMenu; // The menu into which this menu item is inserted + Qt5Menu* mpSubMenu; // Submenu of this item (if defined) + std::unique_ptr mpAction; // action corresponding to this item + std::unique_ptr mpMenu; // menu corresponding to this item + std::shared_ptr mpActionGroup; // empty if it's a separator element + sal_uInt16 mnId; // Item ID + MenuItemType mnType; // Item type + bool mbVisible; // Item visibility. + bool mbEnabled; // Item active. + Image maImage; // Item image +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Object.hxx b/vcl/inc/qt5/Qt5Object.hxx new file mode 100644 index 000000000..0479db2d6 --- /dev/null +++ b/vcl/inc/qt5/Qt5Object.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +class Qt5Frame; +class QWidget; + +class Qt5Object final : public QObject, public SalObject +{ + Q_OBJECT + + SystemEnvData m_aSystemData; + Qt5Frame* m_pParent; + QWidget* m_pQWidget; // main widget, container + QWindow* m_pQWindow; // contained window, used for opengl rendering + QRegion m_pRegion; + +public: + Qt5Object(Qt5Frame* pParent, bool bShow); + ~Qt5Object() override; + + Qt5Frame* frame() const { return m_pParent; } + QWidget* widget() const { return m_pQWidget; } + QWindow* windowHandle() const { return m_pQWindow; } + + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion(sal_uInt32 nRects) override; + virtual void UnionClipRegion(long nX, long nY, long nWidth, long nHeight) override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize(long nX, long nY, long nWidth, long nHeight) override; + virtual void Show(bool bVisible) override; + + virtual void SetForwardKey(bool bEnable) override; + + virtual const SystemEnvData* GetSystemData() const override { return &m_aSystemData; } +}; + +class Qt5ObjectWindow final : public QWindow +{ + Qt5Object& m_rParent; + + bool event(QEvent*) override; + void focusInEvent(QFocusEvent*) override; + void focusOutEvent(QFocusEvent*) override; + void mousePressEvent(QMouseEvent*) override; + void mouseReleaseEvent(QMouseEvent*) override; + // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment in Qt5Widget::event + void keyReleaseEvent(QKeyEvent*) override; + +public: + explicit Qt5ObjectWindow(Qt5Object& rParent); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5OpenGLContext.hxx b/vcl/inc/qt5/Qt5OpenGLContext.hxx new file mode 100644 index 000000000..df5424620 --- /dev/null +++ b/vcl/inc/qt5/Qt5OpenGLContext.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +class QWindow; +class QOpenGLContext; + +class Qt5OpenGLContext final : public OpenGLContext +{ +public: + virtual void initWindow() override; + +private: + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } + virtual bool ImplInit() override; + + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; + + static bool g_bAnyCurrent; + + GLWindow m_aGLWin; + + QWindow* m_pWindow; + QOpenGLContext* m_pContext; +}; diff --git a/vcl/inc/qt5/Qt5Painter.hxx b/vcl/inc/qt5/Qt5Painter.hxx new file mode 100644 index 000000000..51ddc3d69 --- /dev/null +++ b/vcl/inc/qt5/Qt5Painter.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +#include "Qt5Frame.hxx" +#include "Qt5Graphics.hxx" + +class Qt5Painter final : public QPainter +{ + Qt5Graphics& m_rGraphics; + QRegion m_aRegion; + +public: + Qt5Painter(Qt5Graphics& rGraphics, bool bPrepareBrush = false, sal_uInt8 nTransparency = 255); + ~Qt5Painter() + { + if (m_rGraphics.m_pFrame && !m_aRegion.isEmpty()) + m_rGraphics.m_pFrame->GetQWidget()->update(m_aRegion); + } + + void update(int nx, int ny, int nw, int nh) + { + if (m_rGraphics.m_pFrame) + m_aRegion += scaledQRect({ nx, ny, nw, nh }, 1 / m_rGraphics.devicePixelRatioF()); + } + + void update(const QRect& rRect) + { + if (m_rGraphics.m_pFrame) + m_aRegion += scaledQRect(rRect, 1 / m_rGraphics.devicePixelRatioF()); + } + + void update(const QRectF& rRectF) + { + if (m_rGraphics.m_pFrame) + update(scaledQRect(rRectF.toAlignedRect(), 1 / m_rGraphics.devicePixelRatioF())); + } + + void update() + { + if (m_rGraphics.m_pFrame) + m_aRegion += m_rGraphics.m_pFrame->GetQWidget()->rect(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Printer.hxx b/vcl/inc/qt5/Qt5Printer.hxx new file mode 100644 index 000000000..23f5428ca --- /dev/null +++ b/vcl/inc/qt5/Qt5Printer.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +class SalFrame; + +class Qt5Printer final : public PspSalPrinter +{ +public: + Qt5Printer(SalInfoPrinter* pInfoPrinter); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5SvpGraphics.hxx b/vcl/inc/qt5/Qt5SvpGraphics.hxx new file mode 100644 index 000000000..2ea5e6ad9 --- /dev/null +++ b/vcl/inc/qt5/Qt5SvpGraphics.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include "Qt5GraphicsBase.hxx" + +class Qt5Frame; + +class VCLPLUG_QT5_PUBLIC Qt5SvpGraphics : public SvpSalGraphics, public Qt5GraphicsBase +{ + Qt5Frame* const m_pFrame; + +protected: + void handleDamage(const tools::Rectangle&) override; + +public: + Qt5SvpGraphics(Qt5Frame* pFrame); + ~Qt5SvpGraphics() override; + + void updateQWidget() const; + +#if ENABLE_CAIRO_CANVAS + bool SupportsCairo() const override; + cairo::SurfaceSharedPtr + CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, + int height) const override; +#endif // ENABLE_CAIRO_CANVAS + + virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; + + virtual OUString getRenderBackendName() const override { return "qt5svp"; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5SvpSurface.hxx b/vcl/inc/qt5/Qt5SvpSurface.hxx new file mode 100644 index 000000000..0e4da4877 --- /dev/null +++ b/vcl/inc/qt5/Qt5SvpSurface.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include + +class Qt5SvpGraphics; +class OutputDevice; + +namespace cairo +{ +class Qt5SvpSurface final : public Surface +{ + const Qt5SvpGraphics* m_pGraphics; + cairo_t* const m_pCairoContext; + CairoSurfaceSharedPtr m_pSurface; + +public: + /// takes over ownership of passed cairo_surface + explicit Qt5SvpSurface(const CairoSurfaceSharedPtr& pSurface); + /// create surface on subarea of given drawable + explicit Qt5SvpSurface(const Qt5SvpGraphics* pGraphics, int x, int y, int width, int height); + ~Qt5SvpSurface() override; + + // Surface interface + CairoSharedPtr getCairo() const override; + CairoSurfaceSharedPtr getCairoSurface() const override { return m_pSurface; } + SurfaceSharedPtr getSimilar(int nContentType, int width, int height) const override; + + VclPtr createVirtualDevice() const override; + void flush() const override; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5System.hxx b/vcl/inc/qt5/Qt5System.hxx new file mode 100644 index 000000000..63a7e9bde --- /dev/null +++ b/vcl/inc/qt5/Qt5System.hxx @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +class Qt5System final : public SalGenericSystem +{ +public: + virtual unsigned int GetDisplayScreenCount() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel(unsigned int nScreen) override; + virtual int ShowNativeDialog(const OUString& rTitle, const OUString& rMessage, + const std::vector& rButtons) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Timer.hxx b/vcl/inc/qt5/Qt5Timer.hxx new file mode 100644 index 000000000..20b2a4c70 --- /dev/null +++ b/vcl/inc/qt5/Qt5Timer.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +class Qt5Timer final : public QObject, public SalTimer +{ + Q_OBJECT + + QTimer m_aTimer; + +private Q_SLOTS: + void timeoutActivated(); + void startTimer(int); + void stopTimer(); + +Q_SIGNALS: + void startTimerSignal(int); + void stopTimerSignal(); + +public: + Qt5Timer(); + + virtual void Start(sal_uInt64 nMS) override; + virtual void Stop() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Tools.hxx b/vcl/inc/qt5/Qt5Tools.hxx new file mode 100644 index 000000000..1b58750ec --- /dev/null +++ b/vcl/inc/qt5/Qt5Tools.hxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +class Image; +class QImage; + +inline OUString toOUString(const QString& s) +{ + // QString stores UTF16, just like OUString + return OUString(reinterpret_cast(s.data()), s.length()); +} + +inline QString toQString(const OUString& s) +{ + return QString::fromUtf16(reinterpret_cast(s.getStr()), s.getLength()); +} + +inline QRect toQRect(const tools::Rectangle& rRect) +{ + return QRect(rRect.Left(), rRect.Top(), rRect.GetWidth(), rRect.GetHeight()); +} + +inline QRect toQRect(const tools::Rectangle& rRect, const qreal fScale) +{ + return QRect(floor(rRect.Left() * fScale), floor(rRect.Top() * fScale), + ceil(rRect.GetWidth() * fScale), ceil(rRect.GetHeight() * fScale)); +} + +inline QRect scaledQRect(const QRect& rRect, const qreal fScale) +{ + return QRect(floor(rRect.x() * fScale), floor(rRect.y() * fScale), ceil(rRect.width() * fScale), + ceil(rRect.height() * fScale)); +} + +inline tools::Rectangle toRectangle(const QRect& rRect) +{ + return tools::Rectangle(rRect.left(), rRect.top(), rRect.right(), rRect.bottom()); +} + +inline QSize toQSize(const Size& rSize) { return QSize(rSize.Width(), rSize.Height()); } + +inline Size toSize(const QSize& rSize) { return Size(rSize.width(), rSize.height()); } + +inline Point toPoint(const QPoint& rPoint) { return Point(rPoint.x(), rPoint.y()); } + +inline QColor toQColor(const Color& rColor) +{ + return QColor(rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue(), + 255 - rColor.GetTransparency()); +} + +Qt::DropActions toQtDropActions(sal_Int8 dragOperation); +sal_Int8 toVclDropActions(Qt::DropActions dragOperation); +sal_Int8 toVclDropAction(Qt::DropAction dragOperation); +Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation); + +inline QList toQList(const css::uno::Sequence& aSequence) +{ + QList aList; + for (sal_Int32 i : aSequence) + { + aList.append(i); + } + return aList; +} + +static constexpr QImage::Format Qt5_DefaultFormat32 = QImage::Format_ARGB32; + +inline QImage::Format getBitFormat(sal_uInt16 nBitCount) +{ + switch (nBitCount) + { + case 1: + return QImage::Format_Mono; + case 8: + return QImage::Format_Indexed8; + case 24: + return QImage::Format_RGB888; + case 32: + return Qt5_DefaultFormat32; + default: + std::abort(); + break; + } + return QImage::Format_Invalid; +} + +inline sal_uInt16 getFormatBits(QImage::Format eFormat) +{ + switch (eFormat) + { + case QImage::Format_Mono: + return 1; + case QImage::Format_Indexed8: + return 8; + case QImage::Format_RGB888: + return 24; + case Qt5_DefaultFormat32: + case QImage::Format_ARGB32_Premultiplied: + return 32; + default: + std::abort(); + return 0; + } +} + +typedef struct _cairo_surface cairo_surface_t; +struct CairoDeleter +{ + void operator()(cairo_surface_t* pSurface) const; +}; + +typedef std::unique_ptr UniqueCairoSurface; + +sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers); +sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons); + +QImage toQImage(const Image& rImage); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Transferable.hxx b/vcl/inc/qt5/Qt5Transferable.hxx new file mode 100644 index 000000000..0d1cc7050 --- /dev/null +++ b/vcl/inc/qt5/Qt5Transferable.hxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include + +#include +#include +#include + +/** + * Qt5Transferable classes are used to read QMimeData via the XTransferable + * interface. All the functionality is already implemented in the Qt5Transferable. + * + * The specialisations map to the two users, which provide QMimeData: the Clipboard + * and the Drag'n'Drop functionality. + * + * LO itself seem to just accept "text/plain;charset=utf-16", so it relies on the + * backend to convert to this charset, but still offers "text/plain" itself. + * + * It's the "mirror" interface of the Qt5MimeData, which is defined below. + **/ +class Qt5Transferable : public cppu::WeakImplHelper +{ + Qt5Transferable(const Qt5Transferable&) = delete; + + const QMimeData* m_pMimeData; + osl::Mutex m_aMutex; + bool m_bConvertFromLocale; + css::uno::Sequence m_aMimeTypeSeq; + +public: + Qt5Transferable(const QMimeData* pMimeData); + const QMimeData* mimeData() const { return m_pMimeData; } + + css::uno::Sequence SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; + css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; +}; + +/** + * The QClipboard's QMimeData is volatile. As written in the QClipboard::mimeData + * documentation, "the pointer returned might become invalidated when the contents + * of the clipboard changes". Therefore it can just be accessed reliably inside + * the QClipboard's object thread, which is the QApplication's thread, so all of + * the access has to go through RunInMainThread(). + * + * If we detect a QMimeData change, we simply drop reporting any content. In theory + * we can recover in the case where there hadn't been any calls of the XTransferable + * interface, but currently we don't. But we ensure to never report mixed content, + * so we'll just cease operation on QMimeData change. + **/ +class Qt5ClipboardTransferable final : public Qt5Transferable +{ + // to detect in-flight QMimeData changes + const QClipboard::Mode m_aMode; + + bool hasInFlightChanged() const; + +public: + explicit Qt5ClipboardTransferable(const QClipboard::Mode aMode, const QMimeData* pMimeData); + + // these are the same then Qt5Transferable, except they go through RunInMainThread + css::uno::Sequence SAL_CALL getTransferDataFlavors() override; + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; + css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override; +}; + +/** + * Convenience typedef for better code readability + * + * This just uses the QMimeData provided by the QWidgets D'n'D events. + **/ +typedef Qt5Transferable Qt5DnDTransferable; + +/** + * A lazy loading QMimeData for XTransferable reads + * + * This is an interface class to make a XTransferable read accessible as a + * QMimeData. The mime data is just stored inside the XTransferable, never + * in the QMimeData itself! It's objects are just used for QClipboard to read + * the XTransferable data. + * + * Like XTransferable itself, this class should be considered an immutable + * container for mime data. There is no need to ever set any of its data. + * + * LO will offer at least UTF-16, if there is a viable text representation. + * If LO misses to offer a UTF-8 or a locale encoded string, these objects + * will offer them themselves and convert from UTF-16 on demand. + * + * It's the "mirror" interface of the Qt5Transferable. + **/ +class Qt5MimeData final : public QMimeData +{ + friend class Qt5ClipboardTransferable; + + const css::uno::Reference m_aContents; + mutable bool m_bHaveNoCharset; // = uses the locale charset + mutable bool m_bHaveUTF8; + mutable QStringList m_aMimeTypeList; + + QVariant retrieveData(const QString& mimeType, QVariant::Type type) const override; + +public: + explicit Qt5MimeData(const css::uno::Reference& aContents); + + bool hasFormat(const QString& mimeType) const override; + QStringList formats() const override; + + bool deepCopy(QMimeData** const) const; + + css::datatransfer::XTransferable* xTransferable() const { return m_aContents.get(); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5VirtualDevice.hxx b/vcl/inc/qt5/Qt5VirtualDevice.hxx new file mode 100644 index 000000000..89251c96d --- /dev/null +++ b/vcl/inc/qt5/Qt5VirtualDevice.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include + +class Qt5Graphics; +class QImage; +enum class DeviceFormat; + +class Qt5VirtualDevice final : public SalVirtualDevice +{ + std::list m_aGraphics; + std::unique_ptr m_pImage; + DeviceFormat m_eFormat; + QSize m_aFrameSize; + double m_fScale; + +public: + Qt5VirtualDevice(DeviceFormat eFormat, double fScale); + + // SalVirtualDevice + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + virtual bool SetSize(long nNewDX, long nNewDY) override; + virtual bool SetSizeUsingBuffer(long nNewDX, long nNewDY, sal_uInt8* pBuffer) override; + + // SalGeometryProvider + virtual long GetWidth() const override; + virtual long GetHeight() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5Widget.hxx b/vcl/inc/qt5/Qt5Widget.hxx new file mode 100644 index 000000000..159794b2d --- /dev/null +++ b/vcl/inc/qt5/Qt5Widget.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include +#include + +class Qt5Frame; +class Qt5Object; + +class Qt5Widget : public QWidget +{ + Q_OBJECT + + Qt5Frame& m_rFrame; + bool m_bNonEmptyIMPreeditSeen; + int m_nDeltaX; + int m_nDeltaY; + + enum class ButtonKeyState + { + Pressed, + Released + }; + + static void commitText(Qt5Frame&, const QString& aText); + static bool handleKeyEvent(Qt5Frame&, const QWidget&, QKeyEvent*, const ButtonKeyState); + static void handleMouseButtonEvent(const Qt5Frame&, const QMouseEvent*, const ButtonKeyState); + + virtual bool event(QEvent*) override; + + virtual void focusInEvent(QFocusEvent*) override; + virtual void focusOutEvent(QFocusEvent*) override; + // keyPressEvent(QKeyEvent*) is handled via event(QEvent*); see comment + virtual void keyReleaseEvent(QKeyEvent*) override; + virtual void mouseMoveEvent(QMouseEvent*) override; + virtual void mousePressEvent(QMouseEvent*) override; + virtual void mouseReleaseEvent(QMouseEvent*) override; + virtual void dragEnterEvent(QDragEnterEvent*) override; + virtual void dragLeaveEvent(QDragLeaveEvent*) override; + virtual void dragMoveEvent(QDragMoveEvent*) override; + virtual void dropEvent(QDropEvent*) override; + virtual void moveEvent(QMoveEvent*) override; + virtual void paintEvent(QPaintEvent*) override; + virtual void resizeEvent(QResizeEvent*) override; + virtual void showEvent(QShowEvent*) override; + virtual void wheelEvent(QWheelEvent*) override; + virtual void closeEvent(QCloseEvent*) override; + virtual void changeEvent(QEvent*) override; + + void inputMethodEvent(QInputMethodEvent*) override; + QVariant inputMethodQuery(Qt::InputMethodQuery) const override; + +public: + Qt5Widget(Qt5Frame& rFrame, Qt::WindowFlags f = Qt::WindowFlags()); + + Qt5Frame& frame() const { return m_rFrame; } + void endExtTextInput(); + + static bool handleEvent(Qt5Frame&, const QWidget&, QEvent*); + // key events might be propagated further down => call base on false + static inline bool handleKeyReleaseEvent(Qt5Frame&, const QWidget&, QKeyEvent*); + // mouse events are always accepted + static inline void handleMousePressEvent(const Qt5Frame&, const QMouseEvent*); + static inline void handleMouseReleaseEvent(const Qt5Frame&, const QMouseEvent*); +}; + +bool Qt5Widget::handleKeyReleaseEvent(Qt5Frame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent) +{ + return handleKeyEvent(rFrame, rWidget, pEvent, ButtonKeyState::Released); +} + +void Qt5Widget::handleMousePressEvent(const Qt5Frame& rFrame, const QMouseEvent* pEvent) +{ + handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Pressed); +} + +void Qt5Widget::handleMouseReleaseEvent(const Qt5Frame& rFrame, const QMouseEvent* pEvent) +{ + handleMouseButtonEvent(rFrame, pEvent, ButtonKeyState::Released); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/qt5/Qt5XAccessible.hxx b/vcl/inc/qt5/Qt5XAccessible.hxx new file mode 100644 index 000000000..fe8e424e4 --- /dev/null +++ b/vcl/inc/qt5/Qt5XAccessible.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include + +#include + +#include + +#include + +class Qt5Frame; +class Qt5Widget; + +// Wrapper class to hold a css::accessibility::XAccessible object +// while being able to pass it as a QObject +class Qt5XAccessible : public QObject +{ + Q_OBJECT + +public: + Qt5XAccessible(css::uno::Reference xAccessible); + css::uno::Reference m_xAccessible; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/CGHelpers.hxx b/vcl/inc/quartz/CGHelpers.hxx new file mode 100644 index 000000000..cbd9a5e78 --- /dev/null +++ b/vcl/inc/quartz/CGHelpers.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_CGHELPER_HXX +#define INCLUDED_VCL_INC_QUARTZ_CGHELPER_HXX + +#include +#include +#include + +#include + +class CGLayerHolder +{ +private: + CGLayerRef mpLayer; + + // Layer's scaling factor + float mfScale; + +public: + CGLayerHolder() + : mpLayer(nullptr) + , mfScale(1.0) + { + } + + CGLayerHolder(CGLayerRef pLayer, float fScale = 1.0) + : mpLayer(pLayer) + , mfScale(fScale) + { + } + + // Just the size of the layer in pixels + CGSize getSizePixels() const + { + CGSize aSize; + if (mpLayer) + { + aSize = CGLayerGetSize(mpLayer); + } + return aSize; + } + + // Size in points is size in pixels multiplied by the scaling factor + CGSize getSizePoints() const + { + CGSize aSize; + if (mpLayer) + { + const CGSize aLayerSize = getSizePixels(); + aSize.width = aLayerSize.width / mfScale; + aSize.height = aLayerSize.height / mfScale; + } + return aSize; + } + + CGLayerRef get() const { return mpLayer; } + + bool isSet() const { return mpLayer != nullptr; } + + void set(CGLayerRef const& pLayer) { mpLayer = pLayer; } + + float getScale() { return mfScale; } + + void setScale(float fScale) { mfScale = fScale; } +}; + +class CGContextHolder +{ +private: + CGContextRef mpContext; + +public: + CGContextHolder() + : mpContext(nullptr) + { + } + + CGContextHolder(CGContextRef pContext) + : mpContext(pContext) + { + } + + CGContextRef get() const { return mpContext; } + + bool isSet() const { return mpContext != nullptr; } + + void set(CGContextRef const& pContext) { mpContext = pContext; } + + void saveState() { CGContextSaveGState(mpContext); } + + void restoreState() { CGContextRestoreGState(mpContext); } +}; + +#endif // INCLUDED_VCL_INC_QUARTZ_CGHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/common.h b/vcl/inc/quartz/common.h new file mode 100644 index 000000000..003711198 --- /dev/null +++ b/vcl/inc/quartz/common.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_COMMON_H +#define INCLUDED_VCL_INC_QUARTZ_COMMON_H + +#include + +#include +#ifdef MACOSX +#include +#else +#include +#include +#endif +#include + +#include + +// CoreFoundation designers, in their wisdom, decided that CFRelease of NULL +// cause a Crash, yet few API can return NULL when asking for the creation +// of an object, which force us to paper the code with ugly if construct everywhere +// and open the door to very nasty crash on rare occasion +// this macro hide the mess +#define SafeCFRelease(a) do { if(a) { CFRelease(a); (a)=NULL; } } while(false) + +#define round_to_long(a) ((a) >= 0 ? ((long)((a) + 0.5)) : ((long)((a) - 0.5))) + +#include + +std::ostream &operator <<(std::ostream& s, CTFontRef pFont); + +#endif // INCLUDED_VCL_INC_QUARTZ_COMMON_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/ctfonts.hxx b/vcl/inc/quartz/ctfonts.hxx new file mode 100644 index 000000000..89cc55443 --- /dev/null +++ b/vcl/inc/quartz/ctfonts.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_CTFONTS_HXX +#define INCLUDED_VCL_INC_QUARTZ_CTFONTS_HXX + +#include +#include + +SystemFontList* GetCoretextFontList(); +FontAttributes DevFontFromCTFontDescriptor( CTFontDescriptorRef, bool* ); + +#endif // INCLUDED_VCL_INC_QUARTZ_CTFONTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salbmp.h b/vcl/inc/quartz/salbmp.h new file mode 100644 index 000000000..87929249f --- /dev/null +++ b/vcl/inc/quartz/salbmp.h @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_SALBMP_H +#define INCLUDED_VCL_INC_QUARTZ_SALBMP_H + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + + +struct BitmapBuffer; +class BitmapPalette; + +class QuartzSalBitmap : public SalBitmap +{ +public: + CGContextHolder maGraphicContext; + mutable CGImageRef mxCachedImage; + BitmapPalette maPalette; + std::shared_ptr m_pUserBuffer; + std::shared_ptr m_pContextBuffer; + sal_uInt16 mnBits; + int mnWidth; + int mnHeight; + sal_uInt32 mnBytesPerRow; + +public: + QuartzSalBitmap(); + virtual ~QuartzSalBitmap() override; + +public: + + // SalBitmap methods + bool Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) override; + bool Create( const SalBitmap& rSalBmp ) override; + bool Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) override; + bool Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) override; + virtual bool Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false ) override; + + void Destroy() override; + + Size GetSize() const override; + sal_uInt16 GetBitCount() const override; + + BitmapBuffer *AcquireBuffer( BitmapAccessMode nMode ) override; + void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override; + + bool GetSystemData( BitmapSystemData& rData ) override; + + bool ScalingSupported() const override; + bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) override; + bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) override; + +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(CGLayerHolder const & rLayerHolder, int nBitCount, int nX, int nY, int nWidth, int nHeight, bool bFlipped); + +public: + CGImageRef CreateWithMask( const QuartzSalBitmap& rMask, int nX, int nY, int nWidth, int nHeight ) const; + CGImageRef CreateColorMask( int nX, int nY, int nWidth, int nHeight, Color nMaskColor ) const; + CGImageRef CreateCroppedImage( int nX, int nY, int nWidth, int nHeight ) const; + + void doDestroy(); +}; + +#endif // INCLUDED_VCL_INC_QUARTZ_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h new file mode 100644 index 000000000..2ac33fdbd --- /dev/null +++ b/vcl/inc/quartz/salgdi.h @@ -0,0 +1,425 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_SALGDI_H +#define INCLUDED_VCL_INC_QUARTZ_SALGDI_H + +#include + +#include + +#include +#ifdef MACOSX +#include +#include +#include +#else +#include +#include +#endif +#include + +#include +#include + + +#include +#include +#include +#include + +#include +#include +#include + +#include + +class AquaSalFrame; +class FontAttributes; +class CoreTextStyle; +class XorEmulation; + +// CoreText-specific physically available font face +class CoreTextFontFace : public PhysicalFontFace +{ +public: + CoreTextFontFace( const FontAttributes&, sal_IntPtr nFontID ); + virtual ~CoreTextFontFace() override; + + sal_IntPtr GetFontId() const override; + + int GetFontTable( uint32_t nTagCode, unsigned char* ) const; + int GetFontTable( const char pTagName[5], unsigned char* ) const; + + FontCharMapRef GetFontCharMap() const; + bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const; + bool HasChar( sal_uInt32 cChar ) const; + + rtl::Reference CreateFontInstance(const FontSelectPattern&) const override; + +private: + const sal_IntPtr mnFontId; + mutable FontCharMapRef mxCharMap; + mutable vcl::FontCapabilities maFontCapabilities; + mutable bool mbFontCapabilitiesRead; +}; + +class CoreTextStyle final : public LogicalFontInstance +{ + friend rtl::Reference CoreTextFontFace::CreateFontInstance(const FontSelectPattern&) const; + +public: + ~CoreTextStyle() override; + + void GetFontMetric( ImplFontMetricDataRef const & ); + bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; + + CFMutableDictionaryRef GetStyleDict( void ) const { return mpStyleDict; } + + /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0 + float mfFontStretch; + /// text rotation in radian + float mfFontRotation; + /// faux bold - true, if font doesn't have proper bold variants + bool mbFauxBold; + +private: + explicit CoreTextStyle(const PhysicalFontFace&, const FontSelectPattern&); + + hb_font_t* ImplInitHbFont() override; + bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; + + /// CoreText text style object + CFMutableDictionaryRef mpStyleDict; +}; + +// TODO: move into cross-platform headers + +class SystemFontList +{ +public: + SystemFontList( void ); + ~SystemFontList( void ); + + bool Init( void ); + void AddFont( CoreTextFontFace* ); + + void AnnounceFonts( PhysicalFontCollection& ) const; + CoreTextFontFace* GetFontDataFromId( sal_IntPtr nFontId ) const; + +private: + CTFontCollectionRef mpCTFontCollection; + CFArrayRef mpCTFontArray; + + std::unordered_map> maFontContainer; +}; + +class AquaSalGraphics : public SalGraphics +{ + CGLayerHolder maLayer; // Quartz graphics layer + CGContextHolder maContextHolder; // Quartz drawing context + CGContextHolder maBGContextHolder; // Quartz drawing context for CGLayer + CGContextHolder maCSContextHolder; // Quartz drawing context considering the color space + + 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; + + /// path representing current clip region + CGMutablePathRef mxClipPath; + + /// Drawing colors + /// pen color RGBA + RGBAColor maLineColor; + /// brush color RGBA + RGBAColor maFillColor; + + // Device Font settings + rtl::Reference mpTextStyle[MAX_FALLBACK]; + RGBAColor maTextColor; + /// allows text to be rendered without antialiasing + bool mbNonAntialiasedText; + +#ifdef MACOSX + AquaSalFrame* mpFrame; +#endif + + // Graphics types + + /// is this a printer graphics + bool mbPrinter; + /// is this a virtual device graphics + bool mbVirDev; +#ifdef MACOSX + /// is this a window graphics + bool mbWindow; + +#else // IOS + + // mirror AquaSalVirtualDevice::mbForeignContext for SvpSalGraphics objects related to such + bool mbForeignContext; + +#endif + +public: + AquaSalGraphics(); + virtual ~AquaSalGraphics() override; + + bool IsPenVisible() const { return maLineColor.IsVisible(); } + bool IsBrushVisible() const { return maFillColor.IsVisible(); } + + void SetWindowGraphics( AquaSalFrame* pFrame ); + void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY ); + void SetVirDevGraphics(CGLayerHolder const & rLayer, CGContextRef, int nBitDepth = 0); +#ifdef MACOSX + void initResolution( NSWindow* ); + void copyResolution( AquaSalGraphics& ); + void updateResolution(); + + bool IsWindowGraphics() const { return mbWindow; } + AquaSalFrame* getGraphicsFrame() const { return mpFrame; } + void setGraphicsFrame( AquaSalFrame* pFrame ) { mpFrame = pFrame; } +#endif + + void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels + + bool CheckContext(); + CGContextRef GetContext(); +#ifdef MACOSX + void UpdateWindow( NSRect& ); // delivered in NSView coordinates + void RefreshRect( const NSRect& ); +#else + void RefreshRect( const CGRect& ) {} +#endif + 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 SalGraphicsImpl* GetImpl() const override; + + virtual bool setClipRegion( const vcl::Region& ) override; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; + virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; + virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry ) override; + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double rLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool bWindowInvalidate ) override; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) override; + virtual void drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + virtual Color getPixel( long nX, long nY ) override; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) override; + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) override; + + virtual bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uInt32 nSize ) override; + + virtual bool blendBitmap( const SalTwoRect&, + const SalBitmap& rBitmap ) override; + + virtual bool blendAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + + virtual bool drawAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) override; + + bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + + virtual bool drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) override; + + // native widget rendering methods that require mirroring +#ifdef MACOSX +protected: + virtual bool isNativeControlSupported( ControlType nType, ControlPart nPart ) override; + + virtual bool hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + const Point& aPos, bool& rIsInside ) override; + virtual bool drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const OUString& aCaption, const Color& rBackgroundColor ) override; + virtual bool getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override; + +public: +#endif + + // get device resolution + virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override; + // get the depth of the device + virtual sal_uInt16 GetBitCount() const override; + // get the width of the device + virtual long GetGraphicsWidth() const override; + + // set the clip region to empty + virtual void ResetClipRegion() override; + + // set the line color to transparent (= don't draw lines) + virtual void SetLineColor() override; + // set the line color to a specific color + virtual void SetLineColor( Color nColor ) override; + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() override; + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( Color nColor ) override; + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) override; + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + // set the text color to a specific color + virtual void SetTextColor( Color nColor ) override; + // set the font + virtual void SetFont( LogicalFontInstance*, int nFallbackLevel ) override; + // get the current font's metrics + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + // get the repertoire of the current font + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const override; + // graphics must fill supplied font list + virtual void GetDevFontList( PhysicalFontCollection* ) override; + // graphics must drop any cached font info + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) override; + // 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 successful + // parameters: rToFile: contains an 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 corresponding 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 OUString& rToFile, + const PhysicalFontFace* pFont, + const sal_GlyphId* pGlyphIds, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo // out parameter + ) override; + + // 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 + // pDataLen: out parameter, contains the byte length of the returned buffer + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + // frees the font data again + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout( const GenericSalLayout& ) override; + virtual bool supportsOperation( OutDevSupportType ) const override; + virtual OUString getRenderBackendName() const override { return "aqua"; } + + virtual SystemGraphicsData + GetGraphicsData() const override; + +private: + // differences between VCL, Quartz and kHiThemeOrientation coordinate systems + // make some graphics seem to be vertically-mirrored from a VCL perspective + bool IsFlipped() const; + + void ApplyXorContext(); + void Pattern50Fill(); + UInt32 getState( ControlState nState ); + UInt32 getTrackState( ControlState nState ); + static bool GetRawFontData( const PhysicalFontFace* pFontData, + std::vector& rBuffer, + bool* pJustCFF ); +}; + +// --- some trivial inlines + +#ifdef MACOSX + +inline void AquaSalGraphics::RefreshRect( const NSRect& rRect ) +{ + RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height ); +} + +#endif + +#endif // INCLUDED_VCL_INC_QUARTZ_SALGDI_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salgdicommon.hxx b/vcl/inc/quartz/salgdicommon.hxx new file mode 100644 index 000000000..71c40acdf --- /dev/null +++ b/vcl/inc/quartz/salgdicommon.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_SALGDICOMMON_HXX +#define INCLUDED_VCL_INC_QUARTZ_SALGDICOMMON_HXX + +#include + +#include +#ifdef IOS +#include +#else +#include +#endif +#include + +#include +#include + +// abstracting quartz color instead of having to use a CGFloat[] array +class RGBAColor +{ +public: + RGBAColor( ::Color ); + RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET + const CGFloat* AsArray() const { return m_fRGBA; } + bool IsVisible() const { return m_fRGBA[3] > 0; } + void SetAlpha( float fAlpha ) { m_fRGBA[3] = fAlpha; } + + CGFloat GetRed() const { return m_fRGBA[0]; } + CGFloat GetGreen() const { return m_fRGBA[1]; } + CGFloat GetBlue() const { return m_fRGBA[2]; } + CGFloat GetAlpha() const { return m_fRGBA[3]; } +private: + CGFloat m_fRGBA[4]; // red, green, blue, alpha +}; + +inline RGBAColor::RGBAColor( ::Color nColor ) +{ + m_fRGBA[0] = nColor.GetRed() * (1.0/255); + m_fRGBA[1] = nColor.GetGreen() * (1.0/255); + m_fRGBA[2] = nColor.GetBlue() * (1.0/255); + m_fRGBA[3] = 1.0; // opaque +} + +inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ) +{ + m_fRGBA[0] = fRed; + m_fRGBA[1] = fGreen; + m_fRGBA[2] = fBlue; + m_fRGBA[3] = fAlpha; +} + +inline std::ostream &operator <<(std::ostream& s, const RGBAColor &aColor) +{ +#ifndef SAL_LOG_INFO + (void) aColor; +#else + s << "{" << aColor.GetRed() << "," << aColor.GetGreen() << "," << aColor.GetBlue() << "," << aColor.GetAlpha() << "}"; +#endif + return s; +} + +// XOR emulation suckage. +// See http://www.openoffice.org/marketing/ooocon2008/programme/wednesday_1401.pdf +// and https://bugs.freedesktop.org/show_bug.cgi?id=38844 . + +class XorEmulation +{ +public: + XorEmulation(); + ~XorEmulation(); + + void SetTarget( int nWidth, int nHeight, int nBitmapDepth, CGContextRef, CGLayerRef ); + bool UpdateTarget(); + void Enable() { m_bIsEnabled = true; } + void Disable() { m_bIsEnabled = false; } + bool IsEnabled() const { return m_bIsEnabled; } + CGContextRef GetTargetContext() const { return m_xTargetContext; } + CGContextRef GetMaskContext() const { return (m_bIsEnabled ? m_xMaskContext : nullptr); } + +private: + CGLayerRef m_xTargetLayer; + CGContextRef m_xTargetContext; + CGContextRef m_xMaskContext; + CGContextRef m_xTempContext; + sal_uLong* m_pMaskBuffer; + sal_uLong* m_pTempBuffer; + int m_nBufferLongs; + bool m_bIsEnabled; +}; + +#endif // INCLUDED_VCL_INC_QUARTZ_SALGDICOMMON_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salvd.h b/vcl/inc/quartz/salvd.h new file mode 100644 index 000000000..9c2d70798 --- /dev/null +++ b/vcl/inc/quartz/salvd.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_SALVD_H +#define INCLUDED_VCL_INC_QUARTZ_SALVD_H + +#include +#ifdef MACOSX +#include +#else +#include +#endif +#include + +#include + +#include + +class AquaSalGraphics; + +class AquaSalVirtualDevice : public SalVirtualDevice +{ +private: + bool mbGraphicsUsed; // is Graphics used + bool mbForeignContext; // is mxContext from outside VCL + CGContextHolder maBitmapContext; + int mnBitmapDepth; + CGLayerHolder maLayer; // Quartz layer + AquaSalGraphics* mpGraphics; // current VirDev graphics + + long mnWidth; + long mnHeight; + + void Destroy(); + +public: + AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long &nDX, long &nDY, DeviceFormat eFormat, const SystemGraphicsData *pData ); + virtual ~AquaSalVirtualDevice() override; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool SetSize( long nNewDX, long nNewDY ) override; + + long GetWidth() const override + { + return mnWidth; + } + + long GetHeight() const override + { + return mnHeight; + } +}; + +#endif // INCLUDED_VCL_INC_QUARTZ_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/utils.h b/vcl/inc/quartz/utils.h new file mode 100644 index 000000000..2452c151d --- /dev/null +++ b/vcl/inc/quartz/utils.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_QUARTZ_UTILS_H +#define INCLUDED_VCL_INC_QUARTZ_UTILS_H + +#include + +#include +#include +#include +#ifdef MACOSX +#include +#else +#include +#endif +#include + +#include + +OUString GetOUString( CFStringRef ); +OUString GetOUString( const NSString* ); +CFStringRef CreateCFString( const OUString& ); +NSString* CreateNSString( const OUString& ); + +std::ostream &operator <<(std::ostream& s, const CGRect &rRect); +std::ostream &operator <<(std::ostream& s, const CGPoint &rPoint); +std::ostream &operator <<(std::ostream& s, const CGSize &rSize); +std::ostream &operator <<(std::ostream& s, CGColorRef pSize); +std::ostream &operator <<(std::ostream& s, const CGAffineTransform &aXform); + +#endif // INCLUDED_VCL_INC_QUARTZ_UTILS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/regband.hxx b/vcl/inc/regband.hxx new file mode 100644 index 000000000..c7b9e6119 --- /dev/null +++ b/vcl/inc/regband.hxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_REGBAND_HXX +#define INCLUDED_VCL_INC_REGBAND_HXX + +/* + +class ImplRegionBand + +This class handles one y-band of the region. In this band may contain one +or more separations 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. + +*/ + +// element for the list with x-separations +struct ImplRegionBandSep +{ + ImplRegionBandSep* mpNextSep; + long mnXLeft; + long mnXRight; + bool mbRemoved; +}; + +enum class LineType { Ascending, Descending }; + +// element for the list with x-separations +struct ImplRegionBandPoint +{ + ImplRegionBandPoint* mpNextBandPoint; + long mnX; + long mnLineId; + bool mbEndPoint; + LineType meLineType; +}; + +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 temporarily) + 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 : 1; + + // create y-band with boundaries + ImplRegionBand( long nYTop, long nYBottom ); + /** copy y-band 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 + void 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 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 // INCLUDED_VCL_INC_REGBAND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/regionband.hxx b/vcl/inc/regionband.hxx new file mode 100644 index 000000000..a00726148 --- /dev/null +++ b/vcl/inc/regionband.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_INC_REGIONBAND_HXX +#define INCLUDED_VCL_INC_REGIONBAND_HXX + +#include + +#include "regband.hxx" + +#ifdef DBG_UTIL +const char* ImplDbgTestRegionBand(const void*); +#endif + +class RegionBand +{ +private: + friend const char* ImplDbgTestRegionBand(const void*); + + ImplRegionBand* mpFirstBand; // root of the list with y-bands + ImplRegionBand* mpLastCheckedBand; + + void implReset(); + [[nodiscard]] bool CheckConsistency() const; + +public: + RegionBand(); + RegionBand(const RegionBand&); + RegionBand& operator=(const RegionBand&); + RegionBand(const tools::Rectangle&); + ~RegionBand(); + + bool operator==( const RegionBand& rRegionBand ) const; + + [[nodiscard]] bool load(SvStream& rIStrm); + void save(SvStream& rIStrm) const; + + bool isSingleRectangle() const; + ImplRegionBand* ImplGetFirstRegionBand() const { return mpFirstBand; } + void ImplAddMissingBands(const long nTop, const long nBottom); + void InsertBand(ImplRegionBand* pPreviousBand, ImplRegionBand* pBandToInsert); + void processPoints(); + void CreateBandRange(long nYTop, long nYBottom); + void InsertLine(const Point& rStartPt, const Point& rEndPt, long nLineId); + void InsertPoint(const Point &rPoint, long nLineID, bool bEndPoint, LineType eLineType); + bool OptimizeBandList(); + void Move(long nHorzMove, long nVertMove); + void Scale(double fScaleX, double fScaleY); + void InsertBands(long nTop, long nBottom); + static bool InsertSingleBand(ImplRegionBand* pBand, long nYBandPosition); + void Union(long nLeft, long nTop, long nRight, long nBottom); + void Intersect(long nLeft, long nTop, long nRight, long nBottom); + void Union(const RegionBand& rSource); + void Exclude(long nLeft, long nTop, long nRight, long nBottom); + void XOr(long nLeft, long nTop, long nRight, long nBottom); + void Intersect(const RegionBand& rSource); + bool Exclude(const RegionBand& rSource); + void XOr(const RegionBand& rSource); + tools::Rectangle GetBoundRect() const; + bool IsInside(const Point& rPoint) const; + sal_uInt32 getRectangleCount() const; // only users are Region::Intersect, Region::IsRectangle and PSWriter::ImplBmp + void GetRegionRectangles(RectangleVector& rTarget) const; +}; + +#endif // INCLUDED_VCL_INC_REGIONBAND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx new file mode 100644 index 000000000..4244ae1a3 --- /dev/null +++ b/vcl/inc/salbmp.hxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALBMP_HXX +#define INCLUDED_VCL_INC_SALBMP_HXX + +#include +#include +#include +#include +#include +#include + +struct BitmapBuffer; +class Color; +class SalGraphics; +class BitmapPalette; +struct BitmapSystemData; +enum class BmpScaleFlag; + +extern const sal_uLong nVCLRLut[ 6 ]; +extern const sal_uLong nVCLGLut[ 6 ]; +extern const sal_uLong nVCLBLut[ 6 ]; +extern const sal_uLong nVCLDitherLut[ 256 ]; +extern const sal_uLong nVCLLut[ 256 ]; + +class VCL_PLUGIN_PUBLIC SalBitmap +{ +public: + + SalBitmap() + : mnChecksum(0) + , mbChecksumValid(false) + { + } + + virtual ~SalBitmap(); + + virtual bool Create( const Size& rSize, + sal_uInt16 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, + sal_uInt16 nNewBitCount ) = 0; + virtual bool Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false ) = 0; + virtual void Destroy() = 0; + virtual Size GetSize() const = 0; + virtual sal_uInt16 GetBitCount() const = 0; + + virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) = 0; + virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) = 0; + virtual bool GetSystemData( BitmapSystemData& rData ) = 0; + + virtual bool ScalingSupported() const = 0; + virtual bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) = 0; + void DropScaledCache(); + + virtual bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) = 0; + + virtual bool ConvertToGreyscale() + { + return false; + } + virtual bool InterpretAs8Bit() + { + return false; + } + + void GetChecksum(BitmapChecksum& rChecksum) const + { + updateChecksum(); + if (!mbChecksumValid) + rChecksum = 0; // back-compat + else + rChecksum = mnChecksum; + } + + void InvalidateChecksum() + { + mbChecksumValid = false; + } + +protected: + BitmapChecksum mnChecksum; + bool mbChecksumValid; + +protected: + virtual void updateChecksum() const; + // helper function to convert data in 1,2,4 bpp formats to a 8/24/32bpp format + enum class BitConvert + { + A8, + RGB, + BGR, + RGBA, + BGRA + }; + static std::unique_ptr< sal_uInt8[] > convertDataBitCount( const sal_uInt8* src, + int width, int height, int bitCount, int bytesPerRow, const BitmapPalette& palette, + BitConvert type ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/saldatabasic.hxx b/vcl/inc/saldatabasic.hxx new file mode 100644 index 000000000..859117188 --- /dev/null +++ b/vcl/inc/saldatabasic.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALDATABASIC_HXX +#define INCLUDED_VCL_INC_SALDATABASIC_HXX + +#include + +#include "svdata.hxx" +#include "salinst.hxx" + +#ifdef IOS +#include "quartz/salgdi.h" +#endif + +namespace psp +{ + class PrinterInfoManager; +} + +class VCL_PLUGIN_PUBLIC SalData +{ +public: + SalInstance* m_pInstance; // pointer to instance +#ifndef IOS + psp::PrinterInfoManager* m_pPIManager; +#endif + + SalData(); + virtual ~SalData() COVERITY_NOEXCEPT_FALSE; +#ifdef IOS + SystemFontList* mpFontList; + CGColorSpaceRef mxRGBSpace; + CGColorSpaceRef mxGraySpace; + static void ensureThreadAutoreleasePool() {}; +#endif +}; + +inline void SetSalData( SalData* pData ) +{ + ImplGetSVData()->mpSalData = pData; +} + +inline SalData* GetSalData() +{ + return ImplGetSVData()->mpSalData; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salframe.hxx b/vcl/inc/salframe.hxx new file mode 100644 index 000000000..b83138e29 --- /dev/null +++ b/vcl/inc/salframe.hxx @@ -0,0 +1,311 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALFRAME_HXX +#define INCLUDED_VCL_INC_SALFRAME_HXX + +#include "impdel.hxx" +#include "salwtype.hxx" +#include "salgeom.hxx" + +#include +#include + +#include + // complete vcl::Window for SalFrame::CallCallback under -fsanitize=function + +class AllSettings; +class SalGraphics; +class SalBitmap; +class SalMenu; + +struct SalFrameState; +struct SalInputContext; +struct SystemEnvData; + +// SalFrame types +enum class SalFrameToTop { + NONE = 0x00, + RestoreWhenMin = 0x01, + ForegroundTask = 0x02, + GrabFocus = 0x04, + GrabFocusOnly = 0x08 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +namespace vcl { class KeyCode; } + +namespace weld +{ + class Window; +} + +enum class FloatWinPopupFlags; + +// SalFrame styles +enum class SalFrameStyleFlags +{ + NONE = 0x00000000, + DEFAULT = 0x00000001, + MOVEABLE = 0x00000002, + SIZEABLE = 0x00000004, + CLOSEABLE = 0x00000008, + // no shadow effect on Windows XP + NOSHADOW = 0x00000010, + // indicate tooltip windows, so they can always be topmost + TOOLTIP = 0x00000020, + // windows without windowmanager decoration, this typically only applies to floating windows + OWNERDRAWDECORATION = 0x00000040, + // dialogs + DIALOG = 0x00000080, + // the window containing the intro bitmap, aka splashscreen + INTRO = 0x00000100, + // partial fullscreen: fullscreen on one monitor of a multimonitor display + PARTIAL_FULLSCREEN = 0x00800000, + // system child window inside another SalFrame + SYSTEMCHILD = 0x08000000, + // plugged system child window + PLUG = 0x10000000, + // floating window + FLOAT = 0x20000000, + // toolwindows should be painted with a smaller decoration + TOOLWINDOW = 0x40000000, +}; + +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +}; + +// 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 (sal_uInt16(0x0001)) +#define SAL_FRAME_POSSIZE_Y (sal_uInt16(0x0002)) +#define SAL_FRAME_POSSIZE_WIDTH (sal_uInt16(0x0004)) +#define SAL_FRAME_POSSIZE_HEIGHT (sal_uInt16(0x0008)) + +struct SystemParentData; +struct ImplSVEvent; + +/// A SalFrame is a system window (e.g. an X11 window). +class VCL_PLUGIN_PUBLIC SalFrame + : public vcl::DeletionNotifier + , public SalGeometryProvider +{ +private: + // the VCL window corresponding to this frame + VclPtr m_pWindow; + SALFRAMEPROC m_pProc; + Link m_aModalHierarchyHdl; +protected: + mutable std::unique_ptr m_xFrameWeld; +public: + SalFrame(); + virtual ~SalFrame() override; + + SalFrameGeometry maGeometry = {}; ///< absolute, unmirrored values + + // SalGeometryProvider + virtual long GetWidth() const override { return maGeometry.nWidth; } + virtual long GetHeight() const override { return maGeometry.nHeight; } + virtual bool IsOffScreen() const override { return false; } + + // SalGraphics or NULL, but two Graphics for all SalFrames + // must be returned + virtual SalGraphics* AcquireGraphics() = 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(std::unique_ptr pData) = 0; + + virtual void SetTitle( const OUString& rTitle ) = 0; + virtual void SetIcon( sal_uInt16 nIcon ) = 0; + virtual void SetRepresentedURL( const 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; + + // 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, sal_uInt16 nFlags ) = 0; + virtual void GetClientSize( long& rWidth, long& rHeight ) = 0; + virtual void GetWorkArea( tools::Rectangle& rRect ) = 0; + virtual SalFrame* GetParent() const = 0; + // Note: x will be mirrored at parent if UI mirroring is active + SalFrameGeometry GetGeometry() const; + const SalFrameGeometry& GetUnmirroredGeometry() const { return maGeometry; } + + virtual void SetWindowState( const SalFrameState* pState ) = 0; + // return the absolute, unmirrored system frame state + // if this returns false the structure is uninitialised + [[nodiscard]] + virtual bool GetWindowState( SalFrameState* pState ) = 0; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) = 0; + virtual void PositionByToolkit( const tools::Rectangle&, FloatWinPopupFlags ) {}; + + // 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( SalFrameToTop nFlags ) = 0; + + // grab focus to the main widget, can be no-op if the vclplug only uses one widget + virtual void GrabFocus() {} + + // 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() = 0; + virtual void Flush( const tools::Rectangle& ); + + virtual void SetInputContext( SalInputContext* pContext ) = 0; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) = 0; + + virtual OUString GetKeyName( sal_uInt16 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, vcl::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 void UpdateSettings( AllSettings& rSettings ) = 0; + + virtual void Beep() = 0; + + // returns system data (most prominent: window handle) + virtual const SystemEnvData* + GetSystemData() const = 0; + + // get current modifier, button mask and mouse position + struct SalPointerState + { + sal_uLong mnState; + Point maPos; // in frame coordinates + }; + + virtual SalPointerState GetPointerState() = 0; + + virtual KeyIndicatorState GetIndicatorState() = 0; + + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) = 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 internally + // 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; + + virtual void SetApplicationID( const OUString &rApplicationID) = 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( sal_uInt32 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; + + virtual void SetModal(bool /*bModal*/) + { + } + + virtual bool GetModal() const + { + return false; + } + + // return true to indicate tooltips are shown natively, false otherwise + virtual bool ShowTooltip(const OUString& /*rHelpText*/, const tools::Rectangle& /*rHelpArea*/) + { + return false; + } + + // return !0 to indicate popovers are shown natively, 0 otherwise + virtual void* ShowPopover(const OUString& /*rHelpText*/, vcl::Window* /*pParent*/, const tools::Rectangle& /*rHelpArea*/, QuickHelpFlags /*nFlags*/) + { + return nullptr; + } + + // return true to indicate popovers are shown natively, false otherwise + virtual bool UpdatePopover(void* /*nId*/, const OUString& /*rHelpText*/, vcl::Window* /*pParent*/, const tools::Rectangle& /*rHelpArea*/) + { + return false; + } + + // return true to indicate popovers are shown natively, false otherwise + virtual bool HidePopover(void* /*nId*/) + { + return false; + } + + virtual weld::Window* GetFrameWeld() const; + + // Callbacks (independent part in vcl/source/window/winproc.cxx) + // for default message handling return 0 + void SetCallback( vcl::Window* pWindow, SALFRAMEPROC pProc ); + + // returns the instance set + vcl::Window* GetWindow() const { return m_pWindow; } + + void SetModalHierarchyHdl(const Link& rLink) { m_aModalHierarchyHdl = rLink; } + void NotifyModalHierarchy(bool bModal) { m_aModalHierarchyHdl.Call(bModal); } + + // Call the callback set; this sometimes necessary for implementation classes + // that should not know more than necessary about the SalFrame implementation + // (e.g. input methods, printer update handlers). + bool CallCallback( SalEvent nEvent, const void* pEvent ) const + { return m_pProc && m_pProc( m_pWindow, nEvent, pEvent ); } +}; + +#ifdef _WIN32 +bool HasAtHook(); +#endif + +#endif // INCLUDED_VCL_INC_SALFRAME_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx new file mode 100644 index 000000000..8d8e4c96d --- /dev/null +++ b/vcl/inc/salgdi.hxx @@ -0,0 +1,638 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALGDI_HXX +#define INCLUDED_VCL_INC_SALGDI_HXX + +#include + +#include "impfontmetricdata.hxx" +#include "salgdiimpl.hxx" +#include "sallayout.hxx" +#include "SalGradient.hxx" +#include +#include "WidgetDrawInterface.hxx" + +#include + +#include +#include + +class PhysicalFontCollection; +class SalBitmap; +class FontSelectPattern; +class FontAttributes; +class PhysicalFontFace; +class SalLayout; +class ImplLayoutArgs; +namespace tools { class Rectangle; } +class FontSubsetInfo; +class OpenGLContext; +class OutputDevice; +class FreetypeFont; +struct SystemGraphicsData; + +#if ENABLE_CAIRO_CANVAS +struct SystemFontData; +#endif // ENABLE_CAIRO_CANVAS + +namespace basegfx { + class B2DVector; + class B2DPolygon; + class B2DPolyPolygon; +} + +typedef sal_Unicode sal_Ucs; // TODO: use sal_UCS4 instead of sal_Unicode +typedef std::map< sal_Ucs, sal_uInt32 > Ucs2UIntMap; + +// 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_PLUGIN_PUBLIC SalGraphics : protected vcl::WidgetDrawInterface +{ +public: + SalGraphics(); + ~SalGraphics() COVERITY_NOEXCEPT_FALSE override; + + virtual SalGraphicsImpl* GetImpl() const = 0; + + /// Check that our mpImpl is OpenGL and return the context, otherwise NULL. + rtl::Reference GetOpenGLContext() const; + + void setAntiAliasB2DDraw(bool bNew) { m_bAntiAliasB2DDraw = bNew; } + bool getAntiAliasB2DDraw() const { return m_bAntiAliasB2DDraw; } + + // 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 sal_uInt16 GetBitCount() const = 0; + + // get the width of the device + virtual long GetGraphicsWidth() const = 0; + + // set the clip region to empty + virtual void ResetClipRegion() = 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( Color nColor ) = 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( Color nColor ) = 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( Color nColor ) = 0; + + // set the font + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) = 0; + + // release the fonts + void ReleaseFonts() { SetFont( nullptr, 0 ); } + + // get the current font's metrics + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) = 0; + + // get the repertoire of the current font + virtual FontCharMapRef GetFontCharMap() const = 0; + + // get the layout capabilities of the current font + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const = 0; + + // graphics must fill supplied font list + virtual void GetDevFontList( PhysicalFontCollection* ) = 0; + + // graphics must drop any cached font info + virtual void ClearDevFontCache() = 0; + + virtual bool AddTempDevFont( + PhysicalFontCollection*, + const OUString& rFileURL, + const OUString& 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 successful + // parameters: rToFile: contains an 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 corresponding 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 OUString& rToFile, + const PhysicalFontFace* pFont, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo ) = 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 + // pDataLen: out parameter, contains the byte length of the returned buffer + virtual const void* GetEmbedFontData(const PhysicalFontFace* pFont, long* pDataLen) = 0; + + // free the font data again + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) = 0; + + // get the same widths as in CreateFontSubset + // 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 PhysicalFontFace* pFont, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) = 0; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) = 0; + virtual void DrawTextLayout( const GenericSalLayout& ) = 0; + + virtual bool supportsOperation( OutDevSupportType ) const = 0; + + // mirroring specifics + SalLayoutFlags GetLayout() const { return m_nLayout; } + void SetLayout( SalLayoutFlags aLayout ) { m_nLayout = aLayout;} + + void mirror( long& nX, const OutputDevice *pOutDev ) const; + // only called mirror2 to avoid ambiguity + [[nodiscard]] + long mirror2( long nX, const OutputDevice *pOutDev ) 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 ) const; + void mirror( tools::Rectangle& rRect, const OutputDevice*, bool bBack = false ) const; + void mirror( vcl::Region& rRgn, const OutputDevice *pOutDev ) const; + void mirror( ImplControlValue&, const OutputDevice* ) const; + basegfx::B2DPolyPolygon mirror( const basegfx::B2DPolyPolygon& i_rPoly, const OutputDevice *pOutDev ) const; + const basegfx::B2DHomMatrix& getMirror( const OutputDevice *pOutDev ) const; + + // non virtual methods; these do possible coordinate mirroring and + // then delegate to protected virtual methods + bool SetClipRegion( const vcl::Region&, const OutputDevice *pOutDev ); + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + void DrawPixel( long nX, long nY, const OutputDevice *pOutDev ); + void DrawPixel( long nX, long nY, Color nColor, 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( sal_uInt32 nPoints, SalPoint const * pPtAry, const OutputDevice *pOutDev ); + + void DrawPolygon( sal_uInt32 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::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon &i_rPolyPolygon, + double i_fTransparency, + const OutputDevice *i_pOutDev); + + bool DrawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& i_rPolygon, + double i_fTransparency, + double i_fLineWidth, + const std::vector< double >* i_pStroke, // MM01 + basegfx::B2DLineJoin i_eLineJoin, + css::drawing::LineCap i_eLineCap, + double i_fMiterMinimumAngle, + bool bPixelSnapHairline, + const OutputDevice* i_pOutDev); + + bool DrawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry, + const OutputDevice *pOutDev ); + + bool DrawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry, + const OutputDevice *pOutDev ); + + bool DrawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry, + const OutputDevice *pOutDev ); + + bool DrawGradient( + const tools::PolyPolygon& rPolyPoly, + const Gradient& rGradient ); + + bool DrawGradient(basegfx::B2DPolyPolygon const & rPolyPolygon, + SalGradient const & rGradient); + + // CopyArea --> No RasterOp, but ClipRegion + void CopyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + const OutputDevice *pOutDev ); + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + void CopyBits( + const SalTwoRect& rPosAry, + SalGraphics* pSrcGraphics, + const OutputDevice *pOutDev, + const OutputDevice *pSrcOutDev ); + + void DrawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const OutputDevice *pOutDev ); + + void DrawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap, + const OutputDevice *pOutDev ); + + void DrawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor, + const OutputDevice *pOutDev ); + + std::shared_ptr GetBitmap( + long nX, long nY, + long nWidth, long nHeight, + const OutputDevice *pOutDev ); + + Color 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( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + SalInvert nFlags, + const OutputDevice *pOutDev ); + + bool DrawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uInt32 nSize, + const OutputDevice *pOutDev ); + + // native widget rendering functions + + /** + * @see WidgetDrawInterface::isNativeControlSupported + */ + inline bool IsNativeControlSupported(ControlType, ControlPart); + + /** + * @see WidgetDrawInterface::hitTestNativeControl + */ + bool HitTestNativeScrollbar( + ControlPart nPart, + const tools::Rectangle& rControlRegion, + const Point& aPos, + bool& rIsInside, + const OutputDevice *pOutDev ); + + /** + * @see WidgetDrawInterface::drawNativeControl + */ + bool DrawNativeControl( + ControlType nType, + ControlPart nPart, + const tools::Rectangle& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + const OUString& aCaption, + const OutputDevice *pOutDev, + const Color& rBackgroundColor = COL_AUTO ); + + /** + * @see WidgetDrawInterface::getNativeControlRegion + */ + bool GetNativeControlRegion( + ControlType nType, + ControlPart nPart, + const tools::Rectangle& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + tools::Rectangle &rNativeBoundingRegion, + tools::Rectangle &rNativeContentRegion, + const OutputDevice *pOutDev ); + + /** + * @see WidgetDrawInterface::updateSettings + */ + inline bool UpdateSettings(AllSettings&); + + bool BlendBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const OutputDevice *pOutDev ); + + bool BlendAlphaBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalSrcBitmap, + const SalBitmap& rSalMaskBitmap, + const SalBitmap& rSalAlphaBitmap, + const OutputDevice *pOutDev ); + + bool DrawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap, + const OutputDevice *pOutDev ); + + bool DrawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap, + const OutputDevice* pOutDev ); + + bool DrawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency, + const OutputDevice *pOutDev ); + + virtual OUString getRenderBackendName() const; + + virtual SystemGraphicsData GetGraphicsData() const = 0; + +#if ENABLE_CAIRO_CANVAS + + /// Check whether cairo will work + virtual bool SupportsCairo() const = 0; + /// Create Surface from given cairo surface + virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const = 0; + /// Create surface with given dimensions + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const = 0; + /// Create Surface for given bitmap data + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const = 0; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const = 0; + + virtual SystemFontData GetSysFontData( int nFallbacklevel ) const = 0; + +#endif // ENABLE_CAIRO_CANVAS + +protected: + virtual bool setClipRegion( const vcl::Region& ) = 0; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) = 0; + virtual void drawPixel( long nX, long nY, Color nColor ) = 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( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) = 0; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) = 0; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) = 0; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) = 0; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) = 0; + + virtual bool drawGradient( + const tools::PolyPolygon& rPolyPoly, + const Gradient& rGradient ) = 0; + + virtual bool implDrawGradient(basegfx::B2DPolyPolygon const & /*rPolyPolygon*/, + SalGradient const & /*rGradient*/) + { + return false; + } + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + bool bWindowInvalidate ) = 0; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) = 0; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) = 0; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) = 0; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) = 0; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) = 0; + + virtual Color 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( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) = 0; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uInt32 nSize ) = 0; + + /** Blend the bitmap with the current buffer */ + virtual bool blendBitmap( + const SalTwoRect&, + const SalBitmap& rBitmap ) = 0; + + /** Draw the bitmap by blending using the mask and alpha channel */ + virtual bool blendAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) = 0; + + /** 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; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) = 0; + + /** Render solid rectangle with given transparency + * + * @param nX Top left coordinate of rectangle + * @param nY Bottom right coordinate of rectangle + * @param nWidth Width of rectangle + * @param nHeight Height of rectangle + * @param nTransparency Transparency value (0-255) to use. 0 blits and opaque, 255 a + * fully transparent rectangle + * @returns true if successfully drawn, false if not able to draw rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) = 0; + +private: + SalLayoutFlags m_nLayout; //< 0: mirroring off, 1: mirror x-axis + + // for buffering the Mirror-Matrix, see ::getMirror + basegfx::B2DHomMatrix m_aLastMirror; + long m_aLastMirrorW; + +protected: + /// flags which hold the SetAntialiasing() value from OutputDevice + bool m_bAntiAliasB2DDraw : 1; + + inline long GetDeviceWidth(const OutputDevice* pOutDev) const; + + /** + * Handle damage done by drawing with a widget draw override + * + * If a m_pWidgetDraw is set and successfully draws using drawNativeControl, + * this function is called to handle the damage done to the graphics buffer. + * + * @param rDamagedRegion the region damaged by drawNativeControl. + **/ + virtual inline void handleDamage(const tools::Rectangle& rDamagedRegion); + + // native controls + bool initWidgetDrawBackends(bool bForce = false); + + std::unique_ptr m_pWidgetDraw; + vcl::WidgetDrawInterface* forWidget() { return m_pWidgetDraw ? m_pWidgetDraw.get() : this; } +}; + +bool SalGraphics::IsNativeControlSupported(ControlType eType, ControlPart ePart) +{ + return forWidget()->isNativeControlSupported(eType, ePart); +} + +bool SalGraphics::UpdateSettings(AllSettings& rSettings) +{ + return forWidget()->updateSettings(rSettings); +} + +void SalGraphics::handleDamage(const tools::Rectangle&) {} + +#endif // INCLUDED_VCL_INC_SALGDI_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx new file mode 100644 index 000000000..0e62669d6 --- /dev/null +++ b/vcl/inc/salgdiimpl.hxx @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALGDIIMPL_HXX +#define INCLUDED_VCL_INC_SALGDIIMPL_HXX + +#include + +#include +#include + +#include +#include +#include + +#include + +class SalGraphics; +class SalBitmap; +class SalFrame; +class Gradient; +class OpenGLContext; +class SalVirtualDevice; + +class VCL_PLUGIN_PUBLIC SalGraphicsImpl +{ +public: + + virtual ~SalGraphicsImpl(); + + virtual void Init() = 0; + + virtual void DeInit() {} + + virtual void freeResources() = 0; + + virtual OUString getRenderBackendName() const = 0; + + virtual bool setClipRegion( const vcl::Region& ) = 0; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const = 0; + + // get the width of the device + virtual long GetGraphicsWidth() const = 0; + + // set the clip region to empty + virtual void ResetClipRegion() = 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( Color nColor ) = 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( Color nColor ) = 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; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) = 0; + virtual void drawPixel( long nX, long nY, Color nColor ) = 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( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) = 0; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) = 0; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) = 0; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) = 0; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) = 0; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + bool bWindowInvalidate ) = 0; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) = 0; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) = 0; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) = 0; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) = 0; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) = 0; + + virtual Color 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( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) = 0; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uInt32 nSize ) = 0; + + virtual bool blendBitmap( + const SalTwoRect&, + const SalBitmap& rBitmap ) = 0; + + virtual bool blendAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) = 0; + + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) = 0; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) = 0; + + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) = 0; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) = 0; + + virtual bool supportsOperation(OutDevSupportType eType) const = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salgeom.hxx b/vcl/inc/salgeom.hxx new file mode 100644 index 000000000..6adeb7a69 --- /dev/null +++ b/vcl/inc/salgeom.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALGEOM_HXX +#define INCLUDED_VCL_INC_SALGEOM_HXX + +#include + +#include + +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 nDisplayScreenNumber; + + SalFrameGeometry() : + nX( 0 ), + nY( 0 ), + nWidth( 1 ), + nHeight( 1 ), + nLeftDecoration( 0 ), + nTopDecoration( 0 ), + nRightDecoration( 0 ), + nBottomDecoration( 0 ), + nDisplayScreenNumber( 0 ) + {} +}; + +inline std::ostream &operator <<(std::ostream& s, const SalFrameGeometry& rGeom) +{ + s << rGeom.nWidth << "x" << rGeom.nHeight << "@(" << rGeom.nX << "," << rGeom.nY << "):{" + << rGeom.nLeftDecoration << "," << rGeom.nTopDecoration << "," << rGeom.nRightDecoration << "," << rGeom.nBottomDecoration << "}"; + + return s; +} + +/// Interface used to share logic on sizing between +/// SalVirtualDevices and SalFrames +class VCL_PLUGIN_PUBLIC SalGeometryProvider { +public: + virtual ~SalGeometryProvider() {} + virtual long GetWidth() const = 0; + virtual long GetHeight() const = 0; + virtual bool IsOffScreen() const = 0; +}; + +#endif // INCLUDED_VCL_INC_SALGEOM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salinst.hxx b/vcl/inc/salinst.hxx new file mode 100644 index 000000000..36c51d990 --- /dev/null +++ b/vcl/inc/salinst.hxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALINST_HXX +#define INCLUDED_VCL_INC_SALINST_HXX + +#include +#include +#include +#include +#include + +#include "backend/BackendCapabilities.hxx" + +#include "displayconnectiondispatch.hxx" + +#include +#include +#include +#include + +namespace com { +namespace sun { +namespace star { +namespace awt { + class XWindow; +} +} } } +namespace comphelper { class SolarMutex; } +namespace vcl { class Window; } +namespace weld { + class Builder; + class MessageDialog; + class Widget; + class Window; +} +class SystemChildWindow; +struct SystemParentData; +struct SalPrinterQueueInfo; +class ImplJobSetup; +class OpenGLContext; +class SalGraphics; +class SalFrame; +class SalObject; +class SalMenu; +class SalMenuItem; +class SalVirtualDevice; +class SalInfoPrinter; +class SalPrinter; +class SalTimer; +class ImplPrnQueueList; +class SalSystem; +class SalBitmap; +struct SalItemParams; +class SalSession; +struct SystemGraphicsData; +struct SystemWindowData; +class Menu; +enum class VclInputFlags; +enum class SalFrameStyleFlags; + +typedef struct _cairo_font_options cairo_font_options_t; + +class VCL_DLLPUBLIC SalInstance +{ +private: + rtl::Reference< vcl::DisplayConnectionDispatch > m_pEventInst; + const std::unique_ptr m_pYieldMutex; + css::uno::Reference m_clipboard; + +public: + SalInstance(std::unique_ptr pMutex); + virtual ~SalInstance(); + + //called directly after Application::Init + virtual void AfterAppInit() {} + virtual bool SVMainHook(int*) { return false; } + + // Frame + // DisplayName for Unix ??? + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) = 0; + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) = 0; + virtual void DestroyFrame( SalFrame* pFrame ) = 0; + + // Object (System Child Window) + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ) = 0; + virtual void DestroyObject( SalObject* pObject ) = 0; + + // VirtualDevice + // nDX and nDY in pixels + // nBitCount: 0 == default(=as window) / 1 == mono + // pData allows for using a system dependent graphics or device context, + // if a system context is passed in nDX and nDY are updated to reflect + // its size; otherwise these remain unchanged. + virtual std::unique_ptr + CreateVirtualDevice( SalGraphics* pGraphics, + long &rDX, long &rDY, + DeviceFormat eFormat, const SystemGraphicsData *pData = nullptr ) = 0; + + // Printer + // pSetupData->mpDriverData can be 0 + // pSetupData must be updated with the current + // JobSetup + virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) = 0; + virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ) = 0; + virtual std::unique_ptr CreatePrinter( SalInfoPrinter* pInfoPrinter ) = 0; + + virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ) = 0; + virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) = 0; + virtual OUString GetDefaultPrinter() = 0; + + // SalTimer + virtual SalTimer* CreateSalTimer() = 0; + // SalSystem + virtual SalSystem* CreateSalSystem() = 0; + // SalBitmap + virtual std::shared_ptr CreateSalBitmap() = 0; + // BackendCapabilities + virtual std::shared_ptr GetBackendCapabilities() + { + return std::make_shared(); + } + + // YieldMutex + comphelper::SolarMutex* GetYieldMutex(); + sal_uInt32 ReleaseYieldMutexAll(); + void AcquireYieldMutex(sal_uInt32 nCount = 1); + + // return true, if the current thread is the main thread + virtual bool IsMainThread() const = 0; + + /** + * Wait for the next event (if bWait) and dispatch it, + * includes posted events, and timers. + * If bHandleAllCurrentEvents - dispatch multiple posted + * user events. Returns true if events were processed. + */ + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) = 0; + virtual bool AnyInput( VclInputFlags nType ) = 0; + + // menus + virtual std::unique_ptr CreateMenu( bool bMenuBar, Menu* pMenu ); + virtual std::unique_ptr CreateMenuItem( const SalItemParams& pItemData ); + + // may return NULL to disable session management, only used by X11 backend + virtual std::unique_ptr CreateSalSession(); + + virtual OpenGLContext* CreateOpenGLContext() = 0; + + virtual weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile); + virtual weld::Builder* CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile); + virtual weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, + VclButtonsType eButtonType, const OUString& rPrimaryMessage); + virtual weld::Window* GetFrameWeld(const css::uno::Reference& rWindow); + + // methods for XDisplayConnection + + void SetEventCallback( rtl::Reference< vcl::DisplayConnectionDispatch > const & pInstance ) + { m_pEventInst = pInstance; } + + bool CallEventCallback( void const * pEvent, int nBytes ); + + virtual OUString GetConnectionIdentifier() = 0; + + // dtrans implementation + virtual css::uno::Reference< css::uno::XInterface > CreateClipboard( const css::uno::Sequence< css::uno::Any >& i_rArguments ); + virtual css::uno::Reference< css::uno::XInterface > CreateDragSource(); + virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget(); + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) = 0; + + virtual bool hasNativeFileSelection() const { return false; } + // if you override this, make sure to override hasNativeFileSelection too. + virtual css::uno::Reference< css::ui::dialogs::XFilePicker2 > createFilePicker( const css::uno::Reference< css::uno::XComponentContext >& ) + { return css::uno::Reference< css::ui::dialogs::XFilePicker2 >(); } + virtual css::uno::Reference< css::ui::dialogs::XFolderPicker2 > createFolderPicker( const css::uno::Reference< css::uno::XComponentContext >& ) + { return css::uno::Reference< css::ui::dialogs::XFolderPicker2 >(); } + + // callbacks for printer updates + virtual void updatePrinterUpdate() {} + virtual void jobStartedPrinterUpdate() {} + virtual void jobEndedPrinterUpdate() {} + + /// Set the app's (somewhat) magic/main-thread to this one. + virtual void updateMainThread() {} + /// Disconnect that - good for detaching from the JavaVM on Android. + virtual void releaseMainThread() {} + + /// get information about underlying versions + virtual OUString getOSVersion() { return "-"; } + + virtual const cairo_font_options_t* GetCairoFontOptions() { return nullptr; } + + virtual void* CreateGStreamerSink(const SystemChildWindow*) { return nullptr; } +}; + +// called from SVMain +SalInstance* CreateSalInstance(); +void DestroySalInstance( SalInstance* pInst ); + +void SalAbort( const OUString& rErrorText, bool bDumpCore ); + +const OUString& SalGetDesktopEnvironment(); + +#endif // INCLUDED_VCL_INC_SALINST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx new file mode 100644 index 000000000..e94b4c205 --- /dev/null +++ b/vcl/inc/sallayout.hxx @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALLAYOUT_HXX +#define INCLUDED_VCL_INC_SALLAYOUT_HXX + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include // for typedef sal_UCS4 +#include +#include + +#include "impglyphitem.hxx" + +#define MAX_FALLBACK 16 + + +class SalGraphics; +class PhysicalFontFace; +class GenericSalLayout; +enum class SalLayoutFlags; +namespace vcl { + class TextLayoutCache; +} + +// used for managing runs e.g. for BiDi, glyph and script fallback +class ImplLayoutRuns +{ +private: + int mnRunIndex; + std::vector maRuns; + +public: + ImplLayoutRuns() { mnRunIndex = 0; maRuns.reserve(8); } + + void Clear() { maRuns.clear(); } + void AddPos( int nCharPos, bool bRTL ); + void 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 VCL_DLLPUBLIC ImplLayoutArgs +{ +public: + // string related inputs + LanguageTag maLanguageTag; + SalLayoutFlags mnFlags; + const OUString& mrStr; + int mnMinCharPos; + int mnEndCharPos; + + // performance hack + vcl::TextLayoutCache const* m_pTextLayoutCache; + + // positioning related inputs + const DeviceCoordinate* mpDXArray; // in pixel units + DeviceCoordinate mnLayoutWidth; // in pixel units + int mnOrientation; // in 0-3600 system + + // data for bidi and glyph+script fallback + ImplLayoutRuns maRuns; + ImplLayoutRuns maFallbackRuns; + + ImplLayoutArgs( const OUString& rStr, + int nMinCharPos, int nEndCharPos, SalLayoutFlags nFlags, + const LanguageTag& rLanguageTag, + vcl::TextLayoutCache const* pLayoutCache); + + void SetLayoutWidth( DeviceCoordinate nWidth ) { mnLayoutWidth = nWidth; } + void SetDXArray( const DeviceCoordinate* 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 ); + void NeedFallback( int nMinRunPos, int nEndRunPos, bool bRTL ) + { maFallbackRuns.AddRun( nMinRunPos, nEndRunPos, bRTL ); } + // methods used by BiDi and glyph fallback + bool NeedFallback() const + { return !maFallbackRuns.IsEmpty(); } + bool PrepareFallback(); + +private: + void AddRun( int nMinCharPos, int nEndCharPos, bool bRTL ); +}; + +// For nice SAL_INFO logging of ImplLayoutArgs values +std::ostream &operator <<(std::ostream& s, ImplLayoutArgs const &rArgs); + +class MultiSalLayout final : public SalLayout +{ +public: + void DrawText(SalGraphics&) const override; + sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override; + DeviceCoordinate FillDXArray(DeviceCoordinate* pDXArray) const override; + void GetCaretPositions(int nArraySize, long* pCaretXArray) const override; + bool GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, + const PhysicalFontFace** pFallbackFont = nullptr, + int* const pFallbackLevel = nullptr) const override; + bool GetOutline(basegfx::B2DPolyPolygonVector&) const override; + bool IsKashidaPosValid(int nCharPos) const override; + + // used only by OutputDevice::ImplLayout, TODO: make friend + explicit MultiSalLayout( std::unique_ptr pBaseLayout ); + void AddFallback(std::unique_ptr pFallbackLayout, ImplLayoutRuns const &); + bool LayoutText(ImplLayoutArgs&, const SalLayoutGlyphs*) override; + void AdjustLayout(ImplLayoutArgs&) override; + void InitFont() const override; + + void SetIncomplete(bool bIncomplete); + +public: + virtual ~MultiSalLayout() override; + +private: + MultiSalLayout( const MultiSalLayout& ) = delete; + MultiSalLayout& operator=( const MultiSalLayout& ) = delete; + + std::unique_ptr mpLayouts[ MAX_FALLBACK ]; + ImplLayoutRuns maFallbackRuns[ MAX_FALLBACK ]; + int mnLevel; + bool mbIncomplete; +}; + +class VCL_DLLPUBLIC GenericSalLayout : public SalLayout +{ + friend void MultiSalLayout::AdjustLayout(ImplLayoutArgs&); + +public: + GenericSalLayout(LogicalFontInstance&); + ~GenericSalLayout() override; + + void AdjustLayout(ImplLayoutArgs&) final override; + bool LayoutText(ImplLayoutArgs&, const SalLayoutGlyphs*) final override; + void DrawText(SalGraphics&) const final override; + static std::shared_ptr CreateTextLayoutCache(OUString const&); + const SalLayoutGlyphs* GetGlyphs() const final override; + + bool IsKashidaPosValid(int nCharPos) const final override; + + // used by upper layers + DeviceCoordinate GetTextWidth() const final override; + DeviceCoordinate FillDXArray(DeviceCoordinate* pDXArray) const final override; + sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const final override; + void GetCaretPositions(int nArraySize, long* pCaretXArray) const final override; + + // used by display layers + LogicalFontInstance& GetFont() const + { return m_GlyphItems.Impl()->GetFont(); } + + bool GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, + const PhysicalFontFace** pFallbackFont = nullptr, + int* const pFallbackLevel = nullptr) const override; + +private: + // for glyph+font+script fallback + void MoveGlyph(int nStart, long nNewXPos); + void DropGlyph(int nStart); + void Simplify(bool bIsBase); + + GenericSalLayout( const GenericSalLayout& ) = delete; + GenericSalLayout& operator=( const GenericSalLayout& ) = delete; + + void ApplyDXArray(const ImplLayoutArgs&); + void Justify(DeviceCoordinate nNewWidth); + void ApplyAsianKerning(const OUString& rStr); + + void GetCharWidths(DeviceCoordinate* pCharWidths) const; + + void SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool); + + bool HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aNextChar); + + void ParseFeatures(const OUString& name); + + css::uno::Reference mxBreak; + + SalLayoutGlyphs m_GlyphItems; + + OString msLanguage; + std::vector maFeatures; + + hb_set_t* mpVertGlyphs; + const bool mbFuzzing; +}; + +#undef SalGraphics + +#endif // INCLUDED_VCL_INC_SALLAYOUT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx new file mode 100644 index 000000000..c69650354 --- /dev/null +++ b/vcl/inc/salmenu.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALMENU_HXX +#define INCLUDED_VCL_INC_SALMENU_HXX + +#include +#include + +struct SystemMenuData; +class FloatingWindow; +class SalFrame; + +struct SalItemParams +{ + Image aImage; // Image + VclPtr pMenu; // Pointer to Menu + OUString aText; // Menu-Text + MenuItemType eType; // MenuItem-Type + sal_uInt16 nId; // item Id + MenuItemBits nBits; // MenuItem-Bits +}; + +struct SalMenuButtonItem +{ + sal_uInt16 mnId; + Image maImage; + OUString maToolTipText; + + SalMenuButtonItem() : mnId( 0 ) {} + SalMenuButtonItem( sal_uInt16 i_nId, const Image& rImg, const OUString& i_rTTText ) + : mnId( i_nId ), maImage( rImg ), maToolTipText( i_rTTText ) {} +}; + +class VCL_PLUGIN_PUBLIC SalMenuItem +{ +public: + SalMenuItem() {} + virtual ~SalMenuItem(); +}; + +class VCL_PLUGIN_PUBLIC 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 ShowMenuBar( bool ) {} + 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 SetItemBits( unsigned /*nPos*/, MenuItemBits /*nBits*/ ) {} + virtual void CheckItem( unsigned nPos, bool bCheck ) = 0; + virtual void EnableItem( unsigned nPos, bool bEnable ) = 0; + virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText )= 0; + virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage ) = 0; + virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) = 0; + virtual void GetSystemMenuData( SystemMenuData* pData ) = 0; + virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags); + virtual void ShowCloseButton(bool bShow); + virtual bool AddMenuBarButton( const SalMenuButtonItem& ); // return false if not implemented or failure + virtual void RemoveMenuBarButton( sal_uInt16 nId ); + virtual void Update() {} + + virtual bool CanGetFocus() const { return false; } + virtual bool TakeFocus() { return false; } + + // TODO: implement show/hide for the Win/Mac VCL native backends + virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); } + + // 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 tools::Rectangle GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame ); + + virtual int GetMenuBarHeight() const; + + virtual void ApplyPersona(); +}; + +#endif // INCLUDED_VCL_INC_SALMENU_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salobj.hxx b/vcl/inc/salobj.hxx new file mode 100644 index 000000000..6e79e4920 --- /dev/null +++ b/vcl/inc/salobj.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALOBJ_HXX +#define INCLUDED_VCL_INC_SALOBJ_HXX + +#include +#include +#include +#include "salwtype.hxx" + +struct SystemEnvData; + +typedef void (*SALOBJECTPROC)(SystemChildWindow* pInst, SalObjEvent nEvent); + +class VCL_PLUGIN_PUBLIC SalObject +{ + VclPtr m_pInst; + SALOBJECTPROC m_pCallback; + bool m_bMouseTransparent:1, + m_bEraseBackground:1; +public: + SalObject() : m_pInst( nullptr ), m_pCallback( nullptr ), m_bMouseTransparent( false ), m_bEraseBackground( true ) {} + virtual ~SalObject(); + + virtual void ResetClipRegion() = 0; + virtual void BeginSetClipRegion( sal_uInt32 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 */ ) {} // overridden by WinSalObject + virtual void GrabFocus() {} + virtual void Reparent(SalFrame* /*pFrame*/) {} + + virtual void SetForwardKey( bool /* bEnable */ ) {} + + virtual void SetLeaveEnterBackgrounds(const css::uno::Sequence& /*rLeaveArgs*/, const css::uno::Sequence& /*rEnterArgs*/) {} + + virtual const SystemEnvData* GetSystemData() const = 0; + + virtual Size GetOptimalSize() const { return Size(); } + + void SetCallback( SystemChildWindow* pInst, SALOBJECTPROC pProc ) + { m_pInst = pInst; m_pCallback = pProc; } + void CallCallback( SalObjEvent nEvent ) + { if (m_pCallback) m_pCallback( m_pInst, nEvent ); } + + void SetMouseTransparent( bool bMouseTransparent ) + { m_bMouseTransparent = bMouseTransparent; } + bool IsMouseTransparent() const + { return m_bMouseTransparent; } + + void EnableEraseBackground( bool bEnable ) + { m_bEraseBackground = bEnable; } + bool IsEraseBackgroundEnabled() const + { return m_bEraseBackground; } +}; + +#endif // INCLUDED_VCL_INC_SALOBJ_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salprn.hxx b/vcl/inc/salprn.hxx new file mode 100644 index 000000000..9c631dc02 --- /dev/null +++ b/vcl/inc/salprn.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALPRN_HXX +#define INCLUDED_VCL_INC_SALPRN_HXX + +#include +#include +#include + +#include "salptype.hxx" + +#include + +class SalGraphics; +class SalFrame; +class ImplJobSetup; +namespace vcl { class PrinterController; } +namespace weld { class Window; } + +struct VCL_PLUGIN_PUBLIC SalPrinterQueueInfo +{ + OUString maPrinterName; + OUString maDriver; + OUString maLocation; + OUString maComment; + PrintQueueFlags mnStatus; + sal_uInt32 mnJobs; + std::unique_ptr mpPortName; // only used by Windows backend + + SalPrinterQueueInfo(); + ~SalPrinterQueueInfo(); +}; + +class VCL_PLUGIN_PUBLIC SalInfoPrinter +{ +public: + std::vector< PaperInfo > m_aPaperFormats; // all printer supported formats + bool m_bPapersInit; // set to true after InitPaperFormats + + SalInfoPrinter() : m_bPapersInit( false ) {} + virtual ~SalInfoPrinter(); + + // SalGraphics or NULL, but two Graphics for all SalFrames + // must be returned + virtual SalGraphics* AcquireGraphics() = 0; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0; + + virtual bool Setup(weld::Window* 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( JobSetFlags nFlags, ImplJobSetup* pSetupData ) = 0; + + virtual void GetPageInfo( const ImplJobSetup* pSetupData, + long& rOutWidth, long& rOutHeight, + Point& rPageOffset, + Size& rPaperSize ) = 0; + virtual sal_uInt32 GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType ) = 0; + virtual sal_uInt16 GetPaperBinCount( const ImplJobSetup* pSetupData ) = 0; + virtual OUString GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 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; +}; + +class VCL_PLUGIN_PUBLIC SalPrinter +{ + SalPrinter( const SalPrinter& ) = delete; + SalPrinter& operator=( const SalPrinter& ) = delete; + +public: + SalPrinter() {} + virtual ~SalPrinter(); + + virtual bool StartJob( const OUString* pFileName, + const OUString& rJobName, + const OUString& rAppName, + sal_uInt32 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 OUString* pFileName, + const OUString& rJobName, + const OUString& rAppName, + ImplJobSetup* pSetupData, + vcl::PrinterController& rController ); + + virtual bool EndJob() = 0; + virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, bool bNewJobData ) = 0; + virtual void EndPage() = 0; + virtual SalPrinterError GetErrorCode() { return SalPrinterError::NONE; } + +}; + +#endif // INCLUDED_VCL_INC_SALPRN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salptype.hxx b/vcl/inc/salptype.hxx new file mode 100644 index 000000000..9d09c869a --- /dev/null +++ b/vcl/inc/salptype.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALPTYPE_HXX +#define INCLUDED_VCL_INC_SALPTYPE_HXX + +#include + +#include + +enum class JobSetFlags : sal_uInt16 { + ORIENTATION = 1, + PAPERBIN = 2, + PAPERSIZE = 4, + DUPLEXMODE = 8, + ALL = ORIENTATION | PAPERBIN | PAPERSIZE | DUPLEXMODE +}; + +namespace o3tl { + +template<> struct typed_flags: is_typed_flags {}; + +} + +enum class SalPrinterError { + NONE = 0, + General = 1, + Abort = 2 +}; + +class SalPrinter; +typedef long (*SALPRNABORTPROC)( void* pInst, SalPrinter* pPrinter ); + +#endif // INCLUDED_VCL_INC_SALPTYPE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salsession.hxx b/vcl/inc/salsession.hxx new file mode 100644 index 000000000..fb9763bb6 --- /dev/null +++ b/vcl/inc/salsession.hxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALSESSION_HXX +#define INCLUDED_VCL_INC_SALSESSION_HXX + +#include + +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; + + SalSessionSaveRequestEvent( bool bShutdown ) + : SalSessionEvent( SaveRequest ), + m_bShutdown( bShutdown ) + {} +}; + +struct SalSessionShutdownCancelEvent : public SalSessionEvent +{ + SalSessionShutdownCancelEvent() + : SalSessionEvent( ShutdownCancel ) + {} +}; + +struct SalSessionQuitEvent : public SalSessionEvent +{ + SalSessionQuitEvent() + : SalSessionEvent( Quit ) + {} +}; + +typedef void(*SessionProc)(void *pData, SalSessionEvent *pEvent); + +class VCL_PLUGIN_PUBLIC SalSession +{ + SessionProc m_aProc; + void * m_pProcData; +public: + SalSession() + : m_aProc(nullptr) + , m_pProcData(nullptr) + { + } + virtual ~SalSession(); + + void SetCallback( SessionProc aCallback, void * pCallbackData ) + { + m_aProc = aCallback; + m_pProcData = pCallbackData; + } + void CallCallback( SalSessionEvent* pEvent ) + { + if( m_aProc ) + m_aProc( m_pProcData, 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 shutdown in progress + virtual bool cancelShutdown() = 0; +}; + +#endif // INCLUDED_VCL_INC_SALSESSION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salsys.hxx b/vcl/inc/salsys.hxx new file mode 100644 index 000000000..fc80e90d0 --- /dev/null +++ b/vcl/inc/salsys.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALSYS_HXX +#define INCLUDED_VCL_INC_SALSYS_HXX + +#include +#include +#include + +// Button identifier for ShowNativeMessageBox +const int SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK = 1; + +class VCL_PLUGIN_PUBLIC 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 part of one bigger display + + @returns true if screens form one big display + false if screens are distinct and windows cannot + be moved between, or span multiple screens + */ + virtual bool IsUnifiedDisplay() { return true; } + /* 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 GetDisplayBuiltInScreen() { return 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 tools::Rectangle GetDisplayScreenPosSizePixel( 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. + + @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 OUString& rTitle, + const OUString& rMessage ) = 0; + +}; + +VCL_DLLPUBLIC SalSystem* ImplGetSalSystem(); + +#endif // INCLUDED_VCL_INC_SALSYS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/saltimer.hxx b/vcl/inc/saltimer.hxx new file mode 100644 index 000000000..69545ac96 --- /dev/null +++ b/vcl/inc/saltimer.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALTIMER_HXX +#define INCLUDED_VCL_INC_SALTIMER_HXX + +#include +#include +#include "salwtype.hxx" + +/* + * 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_PLUGIN_PUBLIC SalTimer +{ + SALTIMERPROC m_pProc; + +public: + SalTimer() : m_pProc( nullptr ) {} + virtual ~SalTimer() COVERITY_NOEXCEPT_FALSE; + + // AutoRepeat and Restart + virtual void Start( sal_uInt64 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(); + } +}; + +class VersionedEvent +{ + /** + * The "additional event data" members on macOS are integers, so we can't + * use an unsigned integer and rely on the defined unsigned overflow in + * InvalidateEvent(). + */ + sal_Int32 m_nEventVersion; + bool m_bIsValidVersion; + +public: + VersionedEvent() : m_nEventVersion( 0 ), m_bIsValidVersion( false ) {} + + sal_Int32 GetNextEventVersion() + { + InvalidateEvent(); + m_bIsValidVersion = true; + return m_nEventVersion; + } + + void InvalidateEvent() + { + if ( m_bIsValidVersion ) + { + if ( m_nEventVersion == SAL_MAX_INT32 ) + m_nEventVersion = 0; + else + ++m_nEventVersion; + m_bIsValidVersion = false; + } + } + + bool ExistsValidEvent() const + { + return m_bIsValidVersion; + } + + bool IsValidEventVersion( const sal_Int32 nEventVersion ) const + { + return m_bIsValidVersion && nEventVersion == m_nEventVersion; + } +}; + +#endif // INCLUDED_VCL_INC_SALTIMER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salusereventlist.hxx b/vcl/inc/salusereventlist.hxx new file mode 100644 index 000000000..cc5aa88c9 --- /dev/null +++ b/vcl/inc/salusereventlist.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALUSEREVENTLIST_HXX +#define INCLUDED_VCL_INC_SALUSEREVENTLIST_HXX + +#include +#include +#include +#include + +#include +#include + +class SalFrame; +enum class SalEvent; + +typedef o3tl::sorted_vector< SalFrame* > SalFrameSet; + +class VCL_PLUGIN_PUBLIC SalUserEventList +{ +public: + struct SalUserEvent + { + SalFrame* m_pFrame; + void* m_pData; + SalEvent m_nEvent; + + SalUserEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) + : m_pFrame( pFrame ), + m_pData( pData ), + m_nEvent( nEvent ) + {} + + bool operator==(const SalUserEvent &aEvent) const + { + return m_pFrame == aEvent.m_pFrame + && m_pData == aEvent.m_pData + && m_nEvent== aEvent.m_nEvent; + } + }; + +protected: + mutable osl::Mutex m_aUserEventsMutex; + std::list< SalUserEvent > m_aUserEvents; + std::list< SalUserEvent > m_aProcessingUserEvents; + bool m_bAllUserEventProcessedSignaled; + SalFrameSet m_aFrames; + oslThreadIdentifier m_aProcessingThread; + + virtual void ProcessEvent( SalUserEvent aEvent ) = 0; + virtual void TriggerUserEventProcessing() = 0; + virtual void TriggerAllUserEventsProcessed() {} + +public: + SalUserEventList(); + virtual ~SalUserEventList() COVERITY_NOEXCEPT_FALSE; + + inline const SalFrameSet& getFrames() const; + inline SalFrame* anyFrame() const; + void insertFrame( SalFrame* pFrame ); + void eraseFrame( SalFrame* pFrame ); + inline bool isFrameAlive( const SalFrame* pFrame ) const; + + void PostEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); + void RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); + inline bool HasUserEvents() const; + + bool DispatchUserEvents( bool bHandleAllCurrentEvents ); +}; + +inline SalFrame* SalUserEventList::anyFrame() const +{ + if ( m_aFrames.empty() ) + return nullptr; + return *m_aFrames.begin(); +} + +inline bool SalUserEventList::isFrameAlive( const SalFrame* pFrame ) const +{ + auto it = m_aFrames.find( const_cast( pFrame ) ); + return it != m_aFrames.end(); +} + +inline bool SalUserEventList::HasUserEvents() const +{ + osl::MutexGuard aGuard( m_aUserEventsMutex ); + return !(m_aUserEvents.empty() && m_aProcessingUserEvents.empty()); +} + +inline void SalUserEventList::PostEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) +{ + osl::MutexGuard aGuard( m_aUserEventsMutex ); + m_aUserEvents.push_back( SalUserEvent( pFrame, pData, nEvent ) ); + m_bAllUserEventProcessedSignaled = false; + TriggerUserEventProcessing(); +} + +inline const SalFrameSet& SalUserEventList::getFrames() const +{ + return m_aFrames; +} + +#endif // INCLUDED_VCL_INC_SALUSEREVENTLIST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salvd.hxx b/vcl/inc/salvd.hxx new file mode 100644 index 000000000..8a6fe144c --- /dev/null +++ b/vcl/inc/salvd.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALVD_HXX +#define INCLUDED_VCL_INC_SALVD_HXX + +#include "salgeom.hxx" + +class SalGraphics; + +/// A non-visible drawable/buffer (e.g. an X11 Pixmap). +class VCL_PLUGIN_PUBLIC SalVirtualDevice + : public SalGeometryProvider +{ +public: + SalVirtualDevice() {} + virtual ~SalVirtualDevice() override; + + // SalGeometryProvider + virtual bool IsOffScreen() const override { return true; } + + // SalGraphics or NULL, but two Graphics for all SalVirtualDevices + // must be returned + virtual SalGraphics* AcquireGraphics() = 0; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) = 0; + + // Set new size, without saving the old contents + virtual bool SetSize( long nNewDX, long nNewDY ) = 0; + + // Set new size using a buffer at the given address + virtual bool SetSizeUsingBuffer( long nNewDX, long nNewDY, + sal_uInt8 * /* pBuffer */) + { + // Only the headless virtual device has an implementation that uses + // pBuffer (and bTopDown). + return SetSize( nNewDX, nNewDY ); + } +}; + +#endif // INCLUDED_VCL_INC_SALVD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx new file mode 100644 index 000000000..d0ae4ad38 --- /dev/null +++ b/vcl/inc/salvtables.hxx @@ -0,0 +1,1105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "messagedialog.hxx" + +class SalInstanceBuilder : public weld::Builder +{ +protected: + std::unique_ptr m_xBuilder; + VclPtr m_aOwnedToplevel; + +public: + SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile); + + virtual std::unique_ptr + weld_message_dialog(const OString& id, bool bTakeOwnership = true) override; + + virtual std::unique_ptr weld_dialog(const OString& id, + bool bTakeOwnership = true) override; + + virtual std::unique_ptr weld_assistant(const OString& id, + bool bTakeOwnership = true) override; + + virtual std::unique_ptr create_screenshot_window() override; + + virtual std::unique_ptr weld_window(const OString& id, + bool bTakeOwnership = true) override; + + virtual std::unique_ptr weld_widget(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_container(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_box(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_paned(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_frame(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_scrolled_window(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_notebook(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_button(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_menu_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_link_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_toggle_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_radio_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_check_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_scale(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_progress_bar(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_spinner(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_image(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_calendar(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_entry(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_spin_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_metric_spin_button(const OString& id, FieldUnit eUnit, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_formatted_spin_button(const OString& id, bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_time_spin_button(const OString& id, TimeFieldFormat eFormat, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_combo_box(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_entry_tree_view(const OString& containerid, const OString& entryid, + const OString& treeviewid, bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_tree_view(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_icon_view(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_label(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_text_view(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_expander(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr + weld_drawing_area(const OString& id, const a11yref& rA11yImpl = nullptr, + FactoryFunction pUITestFactoryFunction = nullptr, void* pUserData = nullptr, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr weld_menu(const OString& id, + bool bTakeOwnership = true) override; + + virtual std::unique_ptr weld_toolbar(const OString& id, + bool bTakeOwnership = false) override; + + virtual std::unique_ptr create_size_group() override; + + OString get_current_page_help_id() const; + + virtual ~SalInstanceBuilder() override; +}; + +class SalInstanceMenu : public weld::Menu +{ +private: + VclPtr m_xMenu; + + bool m_bTakeOwnership; + sal_uInt16 m_nLastId; + + DECL_LINK(SelectMenuHdl, ::Menu*, bool); + +public: + SalInstanceMenu(PopupMenu* pMenu, bool bTakeOwnership); + virtual OString popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) override; + virtual void set_sensitive(const OString& rIdent, bool bSensitive) override; + virtual void set_active(const OString& rIdent, bool bActive) override; + virtual bool get_active(const OString& rIdent) const override; + virtual void set_label(const OString& rIdent, const OUString& rLabel) override; + virtual OUString get_label(const OString& rIdent) const override; + virtual void set_visible(const OString& rIdent, bool bShow) override; + virtual void clear() override; + virtual void insert(int pos, const OUString& rId, const OUString& rStr, + const OUString* pIconName, VirtualDevice* pImageSurface, + TriState eCheckRadioFalse) override; + virtual void insert_separator(int pos, const OUString& rId) override; + virtual void remove(const OString& rId) override; + virtual int n_children() const override; + PopupMenu* getMenu() const; + virtual ~SalInstanceMenu() override; +}; + +class SalInstanceWidget : public virtual weld::Widget +{ +protected: + VclPtr m_xWidget; + SalInstanceBuilder* m_pBuilder; + +private: + DECL_LINK(EventListener, VclWindowEvent&, void); + DECL_LINK(KeyEventListener, VclWindowEvent&, bool); + DECL_LINK(MouseEventListener, VclSimpleEvent&, void); + DECL_LINK(MnemonicActivateHdl, vcl::Window&, bool); + + const bool m_bTakeOwnership; + bool m_bEventListener; + bool m_bKeyEventListener; + bool m_bMouseEventListener; + int m_nBlockNotify; + +protected: + void ensure_event_listener(); + + // we want the ability to mark key events as handled, so use this variant + // for those, we get all keystrokes in this case, so we will need to filter + // them later + void ensure_key_listener(); + + // we want the ability to know about mouse events that happen in our children + // so use this variant, we will need to filter them later + void ensure_mouse_listener(); + + virtual void HandleEventListener(VclWindowEvent& rEvent); + virtual bool HandleKeyEventListener(VclWindowEvent& rEvent); + virtual void HandleMouseEventListener(VclSimpleEvent& rEvent); + + void set_background(const Color& rColor); + +public: + SalInstanceWidget(vcl::Window* pWidget, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_sensitive(bool sensitive) override; + + virtual bool get_sensitive() const override; + + virtual bool get_visible() const override; + + virtual bool is_visible() const override; + + virtual void set_can_focus(bool bCanFocus) override; + + virtual void grab_focus() override; + + virtual bool has_focus() const override; + + virtual bool is_active() const override; + + virtual void set_has_default(bool has_default) override; + + virtual bool get_has_default() const override; + + virtual void show() override; + + virtual void hide() override; + + virtual void set_size_request(int nWidth, int nHeight) override; + + virtual Size get_size_request() const override; + + virtual Size get_preferred_size() const override; + + virtual float get_approximate_digit_width() const override; + + virtual int get_text_height() const override; + + virtual Size get_pixel_size(const OUString& rText) const override; + + virtual vcl::Font get_font() override; + + virtual OString get_buildable_name() const override; + + virtual void set_help_id(const OString& rId) override; + + virtual OString get_help_id() const override; + + virtual void set_grid_left_attach(int nAttach) override; + + virtual int get_grid_left_attach() const override; + + virtual void set_grid_width(int nCols) override; + + virtual void set_grid_top_attach(int nAttach) override; + + virtual int get_grid_top_attach() const override; + + virtual void set_hexpand(bool bExpand) override; + + virtual bool get_hexpand() const override; + + virtual void set_vexpand(bool bExpand) override; + + virtual bool get_vexpand() const override; + + virtual void set_secondary(bool bSecondary) override; + + virtual void set_margin_top(int nMargin) override; + + virtual void set_margin_bottom(int nMargin) override; + + virtual void set_margin_left(int nMargin) override; + + virtual void set_margin_right(int nMargin) override; + + virtual int get_margin_top() const override; + + virtual int get_margin_bottom() const override; + + virtual int get_margin_left() const override; + + virtual int get_margin_right() const override; + + virtual void set_accessible_name(const OUString& rName) override; + + virtual OUString get_accessible_name() const override; + + virtual OUString get_accessible_description() const override; + + virtual void set_accessible_relation_labeled_by(weld::Widget* pLabel) override; + + virtual void set_accessible_relation_label_for(weld::Widget* pLabeled) override; + + virtual void set_tooltip_text(const OUString& rTip) override; + + virtual OUString get_tooltip_text() const override; + + virtual void connect_focus_in(const Link& rLink) override; + + virtual void connect_mnemonic_activate(const Link& rLink) override; + + virtual void connect_focus_out(const Link& rLink) override; + + virtual void connect_size_allocate(const Link& rLink) override; + + virtual void connect_mouse_press(const Link& rLink) override; + + virtual void connect_mouse_move(const Link& rLink) override; + + virtual void connect_mouse_release(const Link& rLink) override; + + virtual void connect_key_press(const Link& rLink) override; + + virtual void connect_key_release(const Link& rLink) override; + + virtual bool get_extents_relative_to(Widget& rRelative, int& x, int& y, int& width, + int& height) override; + + virtual void grab_add() override; + + virtual bool has_grab() const override; + + virtual void grab_remove() override; + + virtual bool get_direction() const override; + + virtual void set_direction(bool bRTL) override; + + virtual void freeze() override; + + virtual void thaw() override; + + virtual std::unique_ptr weld_parent() const override; + + virtual ~SalInstanceWidget() override; + + vcl::Window* getWidget(); + + void disable_notify_events(); + + bool notify_events_disabled(); + + void enable_notify_events(); + + virtual void help_hierarchy_foreach(const std::function& func) override; + + virtual OUString strip_mnemonic(const OUString& rLabel) const override; + + virtual VclPtr create_virtual_device() const override; + + virtual css::uno::Reference get_drop_target() override; + + virtual void + connect_get_property_tree(const Link& rLink) override; + + virtual void set_stack_background() override; + + virtual void set_toolbar_background() override; + + virtual void set_highlight_background() override; + + virtual void draw(VirtualDevice& rOutput) override; + + SystemWindow* getSystemWindow(); +}; + +class SalInstanceLabel : public SalInstanceWidget, public virtual weld::Label +{ +private: + // Control instead of FixedText so we can also use this for + // SelectableFixedText which is derived from Edit. We just typically need + // [G|S]etText which exists in their shared baseclass + VclPtr m_xLabel; + +public: + SalInstanceLabel(Control* pLabel, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_label(const OUString& rText) override; + + virtual OUString get_label() const override; + + virtual void set_mnemonic_widget(Widget* pTarget) override; + + virtual void set_message_type(weld::EntryMessageType eType) override; + + virtual void set_font(const vcl::Font& rFont) override; +}; + +class SalInstanceContainer : public SalInstanceWidget, public virtual weld::Container +{ +protected: + VclPtr m_xContainer; + +private: + void implResetDefault(const vcl::Window* _pWindow); + +public: + SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + virtual void move(weld::Widget* pWidget, weld::Container* pNewParent) override; + virtual void recursively_unset_default_buttons() override; + virtual css::uno::Reference CreateChildFrame() override; +}; + +class SalInstanceWindow : public SalInstanceContainer, public virtual weld::Window +{ +private: + VclPtr m_xWindow; + + DECL_LINK(HelpHdl, vcl::Window&, bool); + + void override_child_help(vcl::Window* pParent); + + void clear_child_help(vcl::Window* pParent); + +public: + SalInstanceWindow(vcl::Window* pWindow, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_title(const OUString& rTitle) override; + + virtual OUString get_title() const override; + + void help(); + + virtual void set_busy_cursor(bool bBusy) override; + + virtual css::uno::Reference GetXWindow() override; + + virtual void resize_to_request() override; + + virtual void set_modal(bool bModal) override; + + virtual bool get_modal() const override; + + virtual void window_move(int x, int y) override; + + virtual Size get_size() const override; + + virtual Point get_position() const override; + + virtual tools::Rectangle get_monitor_workarea() const override; + + virtual void set_centered_on_parent(bool /*bTrackGeometryRequests*/) override; + + virtual bool get_resizable() const override; + + virtual bool has_toplevel_focus() const override; + + virtual void present() override; + + virtual void set_window_state(const OString& rStr) override; + + virtual OString get_window_state(WindowStateMask nMask) const override; + + virtual SystemEnvData get_system_data() const override; + + virtual void connect_toplevel_focus_changed(const Link& rLink) override; + + virtual void HandleEventListener(VclWindowEvent& rEvent) override; + + virtual void draw(VirtualDevice& rOutput) override; + + virtual weld::ScreenShotCollection collect_screenshot_data() override; + + virtual ~SalInstanceWindow() override; +}; + +class SalInstanceDialog : public SalInstanceWindow, public virtual weld::Dialog +{ +private: + VclPtr<::Dialog> m_xDialog; + + // for calc ref dialog that shrink to range selection widgets and resize back + VclPtr m_xRefEdit; + std::vector> m_aHiddenWidgets; // vector of hidden Controls + long m_nOldEditWidthReq; // Original width request of the input field + sal_Int32 m_nOldBorderWidth; // border width for expanded dialog + + DECL_LINK(PopupScreenShotMenuHdl, const CommandEvent&, bool); + +public: + SalInstanceDialog(::Dialog* pDialog, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual bool runAsync(std::shared_ptr aOwner, + const std::function& rEndDialogFn) override; + + virtual bool runAsync(std::shared_ptr const& rxSelf, + const std::function& rEndDialogFn) override; + + virtual void collapse(weld::Widget* pEdit, weld::Widget* pButton) override; + + virtual void undo_collapse() override; + + virtual void + SetInstallLOKNotifierHdl(const Link& rLink) override; + + virtual int run() override; + + virtual void response(int nResponse) override; + + virtual void add_button(const OUString& rText, int nResponse, + const OString& rHelpId = OString()) override; + + virtual void set_modal(bool bModal) override; + + virtual bool get_modal() const override; + + virtual weld::Button* weld_widget_for_response(int nResponse) override; + + virtual void set_default_response(int nResponse) override; + + virtual weld::Container* weld_content_area() override; +}; + +class WeldTextFilter final : public TextFilter +{ +private: + Link& m_rInsertTextHdl; + +public: + WeldTextFilter(Link& rInsertTextHdl); + + virtual OUString filter(const OUString& rText) override; +}; + +class SalInstanceEntry : public SalInstanceWidget, public virtual weld::Entry +{ +private: + VclPtr<::Edit> m_xEntry; + + DECL_LINK(ChangeHdl, Edit&, void); + DECL_LINK(CursorListener, VclWindowEvent&, void); + DECL_LINK(ActivateHdl, Edit&, bool); + + WeldTextFilter m_aTextFilter; + +public: + SalInstanceEntry(::Edit* pEntry, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_text(const OUString& rText) override; + + virtual OUString get_text() const override; + + virtual void set_width_chars(int nChars) override; + + virtual int get_width_chars() const override; + + virtual void set_max_length(int nChars) override; + + virtual void select_region(int nStartPos, int nEndPos) override; + + bool get_selection_bounds(int& rStartPos, int& rEndPos) override; + + virtual void replace_selection(const OUString& rText) override; + + virtual void set_position(int nCursorPos) override; + + virtual int get_position() const override; + + virtual void set_editable(bool bEditable) override; + + virtual bool get_editable() const override; + + virtual void set_message_type(weld::EntryMessageType eType) override; + + virtual void set_font(const vcl::Font& rFont) override; + + virtual void connect_cursor_position(const Link& rLink) override; + + virtual void set_placeholder_text(const OUString& rText) override; + + Edit& getEntry(); + + void fire_signal_changed(); + + virtual void cut_clipboard() override; + + virtual void copy_clipboard() override; + + virtual void paste_clipboard() override; + + virtual ~SalInstanceEntry() override; +}; + +class SalInstanceSpinButton final : public SalInstanceEntry, public virtual weld::SpinButton +{ +private: + VclPtr m_xButton; + + DECL_LINK(UpDownHdl, SpinField&, void); + DECL_LINK(LoseFocusHdl, Control&, void); + DECL_LINK(OutputHdl, Edit&, bool); + DECL_LINK(InputHdl, sal_Int64*, TriState); + DECL_LINK(ActivateHdl, Edit&, bool); + + double toField(int nValue) const; + + int fromField(double fValue) const; + +public: + SalInstanceSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + + virtual int get_value() const override; + + virtual void set_value(int value) override; + + virtual void set_range(int min, int max) override; + + virtual void get_range(int& min, int& max) const override; + + virtual void set_increments(int step, int /*page*/) override; + + virtual void get_increments(int& step, int& page) const override; + + virtual void set_digits(unsigned int digits) override; + + // SpinButton may be comprised of multiple subwidgets, consider the lot as + // one thing for focus + virtual bool has_focus() const override; + + //so with hh::mm::ss, incrementing mm will not reset ss + void DisableRemainderFactor(); + + //off by default for direct SpinButtons, MetricSpinButton enables it + void SetUseThousandSep(); + + virtual unsigned int get_digits() const override; + + virtual ~SalInstanceSpinButton() override; +}; + +//ComboBox and ListBox have similar apis, ComboBoxes in LibreOffice have an edit box and ListBoxes +//don't. This distinction isn't there in Gtk. Use a template to sort this problem out. +template +class SalInstanceComboBox : public SalInstanceContainer, public virtual weld::ComboBox +{ +protected: + // owner for ListBox/ComboBox UserData + std::vector> m_aUserData; + VclPtr m_xComboBox; + ScopedVclPtr m_xMenuButton; + OUString m_sMenuButtonRow; + +public: + SalInstanceComboBox(vcl_type* pComboBox, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pComboBox, pBuilder, bTakeOwnership) + , m_xComboBox(pComboBox) + { + } + + virtual int get_active() const override + { + const sal_Int32 nRet = m_xComboBox->GetSelectedEntryPos(); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + const OUString* getEntryData(int index) const + { + return static_cast(m_xComboBox->GetEntryData(index)); + } + + // ComboBoxes are comprised of multiple subwidgets, consider the lot as + // one thing for focus + virtual bool has_focus() const override + { + return m_xWidget->HasChildPathFocus() + || (m_xMenuButton && (m_xMenuButton->HasFocus() || m_xMenuButton->InPopupMode())); + } + + virtual OUString get_active_id() const override + { + sal_Int32 nPos = m_xComboBox->GetSelectedEntryPos(); + const OUString* pRet; + if (nPos != LISTBOX_ENTRY_NOTFOUND) + pRet = getEntryData(m_xComboBox->GetSelectedEntryPos()); + else + pRet = nullptr; + if (!pRet) + return OUString(); + return *pRet; + } + + virtual void set_active_id(const OUString& rStr) override + { + for (int i = 0; i < get_count(); ++i) + { + const OUString* pId = getEntryData(i); + if (!pId) + continue; + if (*pId == rStr) + m_xComboBox->SelectEntryPos(i); + } + } + + virtual void set_active(int pos) override + { + if (pos == -1) + { + m_xComboBox->SetNoSelection(); + return; + } + m_xComboBox->SelectEntryPos(pos); + } + + virtual OUString get_text(int pos) const override { return m_xComboBox->GetEntry(pos); } + + virtual OUString get_id(int pos) const override + { + const OUString* pRet = getEntryData(pos); + if (!pRet) + return OUString(); + return *pRet; + } + + virtual void set_id(int row, const OUString& rId) override + { + m_aUserData.emplace_back(std::make_unique(rId)); + m_xComboBox->SetEntryData(row, m_aUserData.back().get()); + } + + virtual void insert_vector(const std::vector& rItems, + bool bKeepExisting) override + { + freeze(); + if (!bKeepExisting) + clear(); + for (const auto& rItem : rItems) + { + insert(-1, rItem.sString, rItem.sId.isEmpty() ? nullptr : &rItem.sId, + rItem.sImage.isEmpty() ? nullptr : &rItem.sImage, nullptr); + } + thaw(); + } + + virtual int get_count() const override { return m_xComboBox->GetEntryCount(); } + + virtual int find_text(const OUString& rStr) const override + { + const sal_Int32 nRet = m_xComboBox->GetEntryPos(rStr); + if (nRet == LISTBOX_ENTRY_NOTFOUND) + return -1; + return nRet; + } + + virtual int find_id(const OUString& rStr) const override + { + for (int i = 0; i < get_count(); ++i) + { + const OUString* pId = getEntryData(i); + if (!pId) + continue; + if (*pId == rStr) + return i; + } + return -1; + } + + virtual void clear() override + { + m_xComboBox->Clear(); + m_aUserData.clear(); + } + + virtual void make_sorted() override + { + m_xComboBox->SetStyle(m_xComboBox->GetStyle() | WB_SORT); + } + + virtual bool get_popup_shown() const override { return m_xComboBox->IsInDropDown(); } + + virtual void connect_popup_toggled(const Link& rLink) override + { + weld::ComboBox::connect_popup_toggled(rLink); + ensure_event_listener(); + } + + void call_signal_custom_render(UserDrawEvent* pEvent) + { + vcl::RenderContext* pRenderContext = pEvent->GetRenderContext(); + auto nPos = pEvent->GetItemId(); + const tools::Rectangle& rRect = pEvent->GetRect(); + const OUString sId = get_id(nPos); + signal_custom_render(*pRenderContext, rRect, pEvent->IsSelected(), sId); + m_xComboBox->DrawEntry(*pEvent); // draw separator + + if (m_xMenuButton && m_xMenuButton->IsVisible() && m_sMenuButtonRow == sId) + { + if (m_xMenuButton->GetParent() != pEvent->GetWindow()) + m_xMenuButton->SetParent(pEvent->GetWindow()); + int nButtonWidth = get_menu_button_width(); + m_xMenuButton->SetSizePixel(Size(nButtonWidth, rRect.GetHeight())); + m_xMenuButton->SetPosPixel(Point(rRect.GetWidth() - nButtonWidth, rRect.getY())); + } + } + + VclPtr create_render_virtual_device() const override + { + auto xRet = VclPtr::Create(); + xRet->SetBackground(Application::GetSettings().GetStyleSettings().GetFieldColor()); + return xRet; + } + + virtual void set_item_menu(const OString& rIdent, weld::Menu* pMenu) override + { + SalInstanceMenu* pInstanceMenu = dynamic_cast(pMenu); + + PopupMenu* pPopup = pInstanceMenu ? pInstanceMenu->getMenu() : nullptr; + + if (!m_xMenuButton) + m_xMenuButton + = VclPtr::Create(m_xComboBox, WB_FLATBUTTON | WB_NOPOINTERFOCUS); + + m_xMenuButton->SetPopupMenu(pPopup); + m_xMenuButton->Show(pPopup != nullptr); + m_sMenuButtonRow = OUString::fromUtf8(rIdent); + } + + int get_menu_button_width() const override + { + const int nButtonWidth = 20; + return nButtonWidth; + } + + void CallHandleEventListener(VclWindowEvent& rEvent) + { + if (rEvent.GetId() == VclEventId::DropdownPreOpen + || rEvent.GetId() == VclEventId::DropdownClose) + { + signal_popup_toggled(); + return; + } + SalInstanceContainer::HandleEventListener(rEvent); + } +}; + +class SalInstanceComboBoxWithoutEdit : public SalInstanceComboBox +{ +private: + DECL_LINK(SelectHdl, ListBox&, void); + +public: + SalInstanceComboBoxWithoutEdit(ListBox* pListBox, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + + virtual OUString get_active_text() const override; + + virtual void remove(int pos) override; + + virtual void insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) override; + + virtual void insert_separator(int pos, const OUString& /*rId*/) override; + + virtual bool has_entry() const override; + + virtual bool changed_by_direct_pick() const override; + + virtual void set_entry_message_type(weld::EntryMessageType /*eType*/) override; + + virtual void set_entry_text(const OUString& /*rText*/) override; + + virtual void select_entry_region(int /*nStartPos*/, int /*nEndPos*/) override; + + virtual bool get_entry_selection_bounds(int& /*rStartPos*/, int& /*rEndPos*/) override; + + virtual void set_entry_width_chars(int /*nChars*/) override; + + virtual void set_entry_max_length(int /*nChars*/) override; + + virtual void set_entry_completion(bool, bool bCaseSensitive = false) override; + + virtual void set_entry_placeholder_text(const OUString&) override; + + virtual void set_entry_editable(bool bEditable) override; + + virtual void cut_entry_clipboard() override; + + virtual void copy_entry_clipboard() override; + + virtual void paste_entry_clipboard() override; + + virtual void set_entry_font(const vcl::Font&) override; + + virtual vcl::Font get_entry_font() override; + + virtual void set_custom_renderer(bool bOn) override; + + virtual int get_max_mru_count() const override; + + virtual void set_max_mru_count(int) override; + + virtual OUString get_mru_entries() const override; + + virtual void set_mru_entries(const OUString&) override; + + virtual void HandleEventListener(VclWindowEvent& rEvent) override; + + virtual ~SalInstanceComboBoxWithoutEdit() override; +}; + +class SalInstanceComboBoxWithEdit : public SalInstanceComboBox +{ +private: + DECL_LINK(ChangeHdl, Edit&, void); + DECL_LINK(EntryActivateHdl, Edit&, bool); + DECL_LINK(SelectHdl, ::ComboBox&, void); + DECL_LINK(UserDrawHdl, UserDrawEvent*, void); + WeldTextFilter m_aTextFilter; + bool m_bInSelect; + +public: + SalInstanceComboBoxWithEdit(::ComboBox* pComboBox, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + + virtual bool has_entry() const override; + + virtual bool changed_by_direct_pick() const override; + + virtual void set_entry_message_type(weld::EntryMessageType eType) override; + + virtual OUString get_active_text() const override; + + virtual void remove(int pos) override; + + virtual void insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) override; + + virtual void insert_separator(int pos, const OUString& /*rId*/) override; + + virtual void set_entry_text(const OUString& rText) override; + + virtual void set_entry_width_chars(int nChars) override; + + virtual void set_entry_max_length(int nChars) override; + + virtual void set_entry_completion(bool bEnable, bool bCaseSensitive = false) override; + + virtual void set_entry_placeholder_text(const OUString& rText) override; + + virtual void set_entry_editable(bool bEditable) override; + + virtual void cut_entry_clipboard() override; + + virtual void copy_entry_clipboard() override; + + virtual void paste_entry_clipboard() override; + + virtual void select_entry_region(int nStartPos, int nEndPos) override; + + virtual bool get_entry_selection_bounds(int& rStartPos, int& rEndPos) override; + + virtual void set_entry_font(const vcl::Font& rFont) override; + + virtual vcl::Font get_entry_font() override; + + virtual void set_custom_renderer(bool bOn) override; + + virtual int get_max_mru_count() const override; + + virtual void set_max_mru_count(int nCount) override; + + virtual OUString get_mru_entries() const override; + + virtual void set_mru_entries(const OUString& rEntries) override; + + virtual void HandleEventListener(VclWindowEvent& rEvent) override; + + virtual ~SalInstanceComboBoxWithEdit() override; +}; + +class SalInstanceButton : public SalInstanceContainer, public virtual weld::Button +{ +private: + VclPtr<::Button> m_xButton; + Link<::Button*, void> const m_aOldClickHdl; + + DECL_LINK(ClickHdl, ::Button*, void); + +public: + SalInstanceButton(::Button* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_label(const OUString& rText) override; + + virtual void set_image(VirtualDevice* pDevice) override; + + virtual void set_image(const css::uno::Reference& rImage) override; + + virtual void set_from_icon_name(const OUString& rIconName) override; + + virtual void set_label_line_wrap(bool wrap) override; + + virtual OUString get_label() const override; + + virtual ~SalInstanceButton() override; +}; + +class SalInstanceNotebook : public SalInstanceContainer, public virtual weld::Notebook +{ +private: + VclPtr m_xNotebook; + mutable std::vector> m_aPages; + std::map, VclPtr>> m_aAddedPages; + + DECL_LINK(DeactivatePageHdl, TabControl*, bool); + DECL_LINK(ActivatePageHdl, TabControl*, void); + +public: + SalInstanceNotebook(TabControl* pNotebook, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual int get_current_page() const override; + + virtual OString get_page_ident(int nPage) const override; + + virtual OString get_current_page_ident() const override; + + virtual weld::Container* get_page(const OString& rIdent) const override; + + virtual void set_current_page(int nPage) override; + + virtual void set_current_page(const OString& rIdent) override; + + virtual void remove_page(const OString& rIdent) override; + + virtual void insert_page(const OString& rIdent, const OUString& rLabel, int nPos) override; + + virtual int get_n_pages() const override; + + virtual OUString get_tab_label_text(const OString& rIdent) const override; + + virtual void set_tab_label_text(const OString& rIdent, const OUString& rText) override; + + virtual ~SalInstanceNotebook() override; +}; + +class SalInstanceMessageDialog : public SalInstanceDialog, public virtual weld::MessageDialog +{ +private: + VclPtr<::MessageDialog> m_xMessageDialog; + +public: + SalInstanceMessageDialog(::MessageDialog* pDialog, SalInstanceBuilder* pBuilder, + bool bTakeOwnership); + + virtual void set_primary_text(const OUString& rText) override; + + virtual OUString get_primary_text() const override; + + virtual void set_secondary_text(const OUString& rText) override; + + virtual OUString get_secondary_text() const override; + + virtual weld::Container* weld_message_area() override; +}; + +class SalInstanceCheckButton : public SalInstanceButton, public virtual weld::CheckButton +{ +private: + VclPtr m_xCheckButton; + + DECL_LINK(ToggleHdl, CheckBox&, void); + +public: + SalInstanceCheckButton(CheckBox* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership); + + virtual void set_active(bool active) override; + + virtual bool get_active() const override; + + virtual void set_inconsistent(bool inconsistent) override; + + virtual bool get_inconsistent() const override; + + virtual ~SalInstanceCheckButton() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/salwtype.hxx b/vcl/inc/salwtype.hxx new file mode 100644 index 000000000..fc8aeb497 --- /dev/null +++ b/vcl/inc/salwtype.hxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALWTYPE_HXX +#define INCLUDED_VCL_INC_SALWTYPE_HXX + +#include +#include +#include +#include +#include + +class LogicalFontInstance; +class SalGraphics; +class SalFrame; +class SalObject; +namespace vcl { class Window; } +enum class InputContextFlags; +enum class WindowStateMask; +enum class WindowStateState; +enum class ExtTextInputAttr; +enum class ModKeyFlags; + +enum class SalEvent { + NONE, + MouseMove, + MouseLeave, + MouseButtonDown, + MouseButtonUp, + KeyInput, + KeyUp, + KeyModChange, + Paint, + Resize, + GetFocus, + LoseFocus, + Close, + Shutdown, + SettingsChanged, + PrinterChanged, + DisplayChanged, + FontChanged, + WheelMouse, + UserEvent, + MouseActivate, + ExtTextInput, + EndExtTextInput, + ExtTextInputPos, + InputContextChange, + Move, + MoveResize, + ClosePopups, + ExternalKeyInput, + ExternalKeyUp, + MenuCommand, + MenuHighlight, + MenuActivate, + MenuDeactivate, + ExternalMouseMove, + ExternalMouseButtonDown, + ExternalMouseButtonUp, + InputLanguageChange, + ShowDialog, + MenuButtonCommand, + SurroundingTextRequest, + SurroundingTextSelectionChange, + StartReconversion, + QueryCharPosition, + Swipe, + LongPress, + ExternalGesture, + Gesture, +}; + +// 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 +{ + sal_uInt64 mnTime; // Time in ms, when event is created + long mnX; // X-Position (Pixel, TopLeft-Output) + long mnY; // Y-Position (Pixel, TopLeft-Output) + sal_uInt16 mnButton; // 0-MouseMove/MouseLeave, MOUSE_LEFT, MOUSE_RIGHT, MOUSE_MIDDLE + sal_uInt16 mnCode; // SV-Modifiercode (KEY_SHIFT|KEY_MOD1|KEY_MOD2|MOUSE_LEFT|MOUSE_MIDDLE|MOUSE_RIGHT) +}; + +// KEYINPUT and KEYUP +struct SalKeyEvent +{ + sal_uInt16 mnCode; // SV-KeyCode (KEY_xxx | KEY_SHIFT | KEY_MOD1 | KEY_MOD2) + sal_uInt16 mnCharCode; // SV-CharCode + sal_uInt16 mnRepeat; // Repeat-Count (KeyInputs-1) +}; + +// MENUEVENT +struct SalMenuEvent +{ + sal_uInt16 mnId; // Menu item ID + void* mpMenu; // pointer to VCL menu (class Menu) + + SalMenuEvent() : mnId( 0 ), mpMenu( nullptr ) {} + SalMenuEvent( sal_uInt16 i_nId, void* i_pMenu ) + : mnId( i_nId ), mpMenu( i_pMenu ) {} +}; + +// KEYMODCHANGE +struct SalKeyModEvent +{ + bool mbDown; // Whether the change occurred on a key down event + sal_uInt16 mnCode; // SV-Modifiercode (KEY_SHIFT|KEY_MOD1|KEY_MOD2) + ModKeyFlags mnModKeyCode; // extended Modifier (MODKEY_LEFT,MODKEY_RIGHT,MODKEY_PRESS,MODKEY_RELEASE) +}; + +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 ) + {} +}; + +#define SAL_WHEELMOUSE_EVENT_PAGESCROLL (sal_uLong(0xFFFFFFFF)) +struct SalWheelMouseEvent +{ + sal_uInt64 mnTime; // Time in ms, when event is created + long mnX; // X-Position (Pixel, TopLeft-Output) + long mnY; // Y-Position (Pixel, TopLeft-Output) + long mnDelta; // Number of rotations + long mnNotchDelta; // Number of fixed rotations + double mnScrollLines; // Actual number of lines to scroll + sal_uInt16 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 touch devices) + + SalWheelMouseEvent() + : mnTime( 0 ), mnX( 0 ), mnY( 0 ), mnDelta( 0 ), mnNotchDelta( 0 ), mnScrollLines( 0 ), mnCode( 0 ), mbHorz( false ), mbDeltaIsPixel( false ) + {} +}; + +struct SalExtTextInputEvent +{ + OUString maText; // Text + const ExtTextInputAttr* mpTextAttr; // Text-Attribute + sal_Int32 mnCursorPos; // Cursor-Position + sal_uInt8 mnCursorFlags; // EXTTEXTINPUT_CURSOR_xxx +}; + +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 + SalExtTextInputPosEvent() + : mnX(0) + , mnY(0) + , mnWidth(0) + , mnHeight(0) + , mnExtWidth(0) + , mbVertical(false) + { + } +}; + +struct SalInputContextChangeEvent +{ +}; + +struct SalSurroundingTextRequestEvent +{ + OUString maText; // Text + sal_uLong mnStart; // The beginning index of selected range + sal_uLong mnEnd; // The end index of selected range +}; + +struct SalSurroundingTextSelectionChangeEvent +{ + sal_uLong mnStart; // The beginning index of selected range + sal_uLong mnEnd; // The end index of selected range +}; + +struct SalQueryCharPositionEvent +{ + bool mbValid; // The data is valid or not. + sal_uLong mnCharPos; // The index of character in a composition. + bool mbVertical; // The text is vertical or not. + long mnCursorBoundX; // The cursor bounds corresponding to the character specified by mnCharPos - X + long mnCursorBoundY; // The cursor bounds corresponding to the character specified by mnCharPos - Y + long mnCursorBoundWidth; // The cursor bounds corresponding to the character specified by mnCharPos - Width + long mnCursorBoundHeight; // The cursor bounds corresponding to the character specified by mnCharPos - Height +}; + +typedef bool (*SALFRAMEPROC)( vcl::Window* pInst, SalEvent nEvent, const void* pEvent ); + +enum class SalObjEvent { + GetFocus = 1, + LoseFocus = 2, + ToTop = 3 +}; + +struct SalFrameState +{ + WindowStateMask mnMask; + long mnX; + long mnY; + long mnWidth; + long mnHeight; + long mnMaximizedX; + long mnMaximizedY; + long mnMaximizedWidth; + long mnMaximizedHeight; + WindowStateState mnState; +}; + +struct SalInputContext +{ + rtl::Reference mpFont; + InputContextFlags mnOptions; +}; + +struct SalSwipeEvent +{ + double mnVelocityX; + double mnVelocityY; + long mnX; + long mnY; +}; + +struct SalLongPressEvent +{ + long mnX; + long mnY; +}; + +struct SalGestureEvent +{ + GestureEventType meEventType; + PanningOrientation meOrientation; + double mfOffset; + long mnX; + long mnY; +}; + +typedef void (*SALTIMERPROC)(); + +#endif // INCLUDED_VCL_INC_SALWTYPE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/scanlinewriter.hxx b/vcl/inc/scanlinewriter.hxx new file mode 100644 index 000000000..a5b892b02 --- /dev/null +++ b/vcl/inc/scanlinewriter.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SCANLINEWRITER_HXX +#define INCLUDED_VCL_INC_SCANLINEWRITER_HXX + +#include +#include + +namespace vcl +{ + +// Write color information for 1, 4 and 8 bit palette bitmap scanlines. +class ScanlineWriter +{ + BitmapPalette& maPalette; + sal_uInt8 const mnColorsPerByte; // number of colors that are stored in one byte + sal_uInt8 const mnColorBitSize; // number of bits a color takes + sal_uInt8 const mnColorBitMask; // bit mask used to isolate the color + sal_uInt8* mpCurrentScanline; + long mnX; + +public: + + ScanlineWriter(BitmapPalette& aPalette, sal_Int8 nColorsPerByte) + : maPalette(aPalette) + , mnColorsPerByte(nColorsPerByte) + , mnColorBitSize(8 / mnColorsPerByte) // bit size is number of bit in a byte divided by number of colors per byte (8 / 2 = 4 for 4-bit) + , mnColorBitMask((1 << mnColorBitSize) - 1) // calculate the bit mask from the bit size + , mpCurrentScanline(nullptr) + , mnX(0) + {} + + static std::unique_ptr Create(sal_uInt16 nBits, BitmapPalette& aPalette) + { + switch(nBits) + { + case 1: + return std::make_unique(aPalette, 8); + case 4: + return std::make_unique(aPalette, 2); + case 8: + return std::make_unique(aPalette, 1); + default: + abort(); + } + } + + void writeRGB(sal_uInt8 nR, sal_uInt8 nG, sal_uInt8 nB) + { + // calculate to which index we will write + long nScanlineIndex = mnX / mnColorsPerByte; + + // calculate the number of shifts to get the color information to the right place + long nShift = (8 - mnColorBitSize) - ((mnX % mnColorsPerByte) * mnColorBitSize); + + sal_uInt16 nColorIndex = maPalette.GetBestIndex(BitmapColor(nR, nG, nB)); + mpCurrentScanline[nScanlineIndex] &= ~(mnColorBitMask << nShift); // clear + mpCurrentScanline[nScanlineIndex] |= (nColorIndex & mnColorBitMask) << nShift; // set + mnX++; + } + + void nextLine(sal_uInt8* pScanline) + { + mnX = 0; + mpCurrentScanline = pScanline; + } +}; + +} // namespace vcl + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/schedulerimpl.hxx b/vcl/inc/schedulerimpl.hxx new file mode 100644 index 000000000..38f27a665 --- /dev/null +++ b/vcl/inc/schedulerimpl.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SCHEDULERIMPL_HXX +#define INCLUDED_VCL_INC_SCHEDULERIMPL_HXX + +#include "salwtype.hxx" +#include +#include + +class Task; + +// Internal scheduler record holding intrusive linked list pieces +struct ImplSchedulerData final +{ + ImplSchedulerData* mpNext; ///< Pointer to the next element in list + Task* mpTask; ///< Pointer to VCL Task instance + bool mbInScheduler; ///< Task currently processed? + sal_uInt64 mnUpdateTime; ///< Last Update Time + TaskPriority mePriority; ///< Task priority + + const char *GetDebugName() const; +}; + +class SchedulerMutex final +{ + sal_uInt32 mnLockDepth; + osl::Mutex maMutex; + +public: + SchedulerMutex() : mnLockDepth( 0 ) {} + + void acquire( sal_uInt32 nLockCount = 1 ); + sal_uInt32 release( bool bUnlockAll = false ); + sal_uInt32 lockDepth() const { return mnLockDepth; } +}; + +class SchedulerGuard final +{ +public: + SchedulerGuard() + { + Scheduler::Lock(); + } + + ~SchedulerGuard() + { + Scheduler::Unlock(); + } +}; + +#endif // INCLUDED_VCL_INC_SCHEDULERIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/scrptrun.h b/vcl/inc/scrptrun.h new file mode 100644 index 000000000..b663deeed --- /dev/null +++ b/vcl/inc/scrptrun.h @@ -0,0 +1,158 @@ +/* + ******************************************************************************* + * + * Copyright (c) 1995-2013 International Business Machines Corporation and others + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * provided that the above copyright notice(s) and this permission notice appear + * in all copies of the Software and that both the above copyright notice(s) and + * this permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN + * NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE + * LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall not be + * used in advertising or otherwise to promote the sale, use or other dealings in + * this Software without prior written authorization of the copyright holder. + * + ******************************************************************************* + * file name: scrptrun.h + * + * created on: 10/17/2001 + * created by: Eric R. Mader + */ + +#ifndef INCLUDED_VCL_INC_SCRPTRUN_H +#define INCLUDED_VCL_INC_SCRPTRUN_H + +#include + +#include +#include +#include + +namespace vcl { + +struct ParenStackEntry +{ + int32_t pairIndex; + UScriptCode scriptCode; + ParenStackEntry() + : pairIndex(0) + , scriptCode(USCRIPT_INVALID_CODE) + { + } +}; + +class ScriptRun final : public icu::UObject { +public: + + ScriptRun(const UChar chars[], int32_t length); + + void reset(); + + void reset(int32_t start, int32_t count); + + void reset(const UChar chars[], int32_t start, int32_t length); + + int32_t getScriptStart() const; + + int32_t getScriptEnd() const; + + UScriptCode getScriptCode() const; + + UBool next(); + + /** +s * ICU "poor man's RTTI", returns a UClassID for the actual class. + * + * @stable ICU 2.2 + */ + virtual UClassID getDynamicClassID() const override { return getStaticClassID(); } + + /** + * ICU "poor man's RTTI", returns a UClassID for this class. + * + * @stable ICU 2.2 + */ + static UClassID getStaticClassID() { return static_cast(const_cast(&fgClassID)); } + +private: + + int32_t charStart; + int32_t charLimit; + const UChar *charArray; + + int32_t scriptStart; + int32_t scriptEnd; + UScriptCode scriptCode; + + std::vector parenStack; + int32_t parenSP; + + /** + * The address of this static class variable serves as this class's ID + * for ICU "poor man's RTTI". + */ + static const char fgClassID; +}; + +inline ScriptRun::ScriptRun(const UChar chars[], int32_t length) +{ + reset(chars, 0, length); +} + +inline int32_t ScriptRun::getScriptStart() const +{ + return scriptStart; +} + +inline int32_t ScriptRun::getScriptEnd() const +{ + return scriptEnd; +} + +inline UScriptCode ScriptRun::getScriptCode() const +{ + return scriptCode; +} + +inline void ScriptRun::reset() +{ + scriptStart = charStart; + scriptEnd = charStart; + scriptCode = USCRIPT_INVALID_CODE; + parenSP = -1; + parenStack.resize(128); +} + +inline void ScriptRun::reset(int32_t start, int32_t length) +{ + charStart = start; + charLimit = start + length; + + reset(); +} + +inline void ScriptRun::reset(const UChar chars[], int32_t start, int32_t length) +{ + charArray = chars; + + reset(start, length); +} + +} + +#endif diff --git a/vcl/inc/scrwnd.hxx b/vcl/inc/scrwnd.hxx new file mode 100644 index 000000000..c55fbd985 --- /dev/null +++ b/vcl/inc/scrwnd.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SCRWND_HXX +#define INCLUDED_VCL_INC_SCRWND_HXX + +#include +#include +#include + +class Timer; + +enum class WheelMode { + NONE = 0x0000, + VH = 0x0001, + V = 0x0002, + H = 0x0004, + ScrollVH = 0x0008, + ScrollV = 0x0010, + ScrollH = 0x0020 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +class ImplWheelWindow final : public FloatingWindow +{ +private: + + std::vector maImgList; + Point maLastMousePos; + Point maCenter; + std::unique_ptr mpTimer; + sal_uInt64 mnRepaintTime; + sal_uInt64 mnTimeout; + WheelMode mnWheelMode; + sal_uLong mnMaxWidth; + sal_uLong mnActDist; + long mnActDeltaX; + long mnActDeltaY; + void ImplCreateImageList(); + void ImplSetRegion(const Bitmap& rRegionBmp); + using Window::ImplGetMousePointer; + PointerStyle ImplGetMousePointer( long nDistX, long nDistY ); + void ImplDrawWheel(vcl::RenderContext& rRenderContext); + void ImplRecalcScrollValues(); + + DECL_LINK(ImplScrollHdl, Timer *, void); + + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + +public: + + explicit ImplWheelWindow( vcl::Window* pParent ); + virtual ~ImplWheelWindow() override; + virtual void dispose() override; + + void ImplStop(); + void ImplSetWheelMode( WheelMode nWheelMode ); +}; + +#endif // INCLUDED_VCL_INC_SCRWND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/sft.hxx b/vcl/inc/sft.hxx new file mode 100644 index 000000000..aca60a456 --- /dev/null +++ b/vcl/inc/sft.hxx @@ -0,0 +1,752 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** + * @file sft.hxx + * @brief Sun Font Tools + */ + +/* + * 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 + * + * 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 INCLUDED_VCL_INC_SFT_HXX +#define INCLUDED_VCL_INC_SFT_HXX + +#include +#include +#include + +#include +#include +#include +#include + +namespace vcl +{ + +/*@{*/ + typedef sal_Int32 F16Dot16; /**< fixed: 16.16 */ +/*@}*/ + +/** Return value of OpenTTFont() and CreateT3FromTTGlyphs() */ + enum class SFErrCodes { + Ok, /**< no error */ + BadFile, /**< file not found */ + FileIo, /**< file I/O error */ + Memory, /**< memory allocation error */ + GlyphNum, /**< incorrect number of glyphs */ + BadArg, /**< incorrect arguments */ + TtFormat, /**< incorrect TrueType font format */ + 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) */ + }; +#endif /* FW_THIN */ + +/** Value of the width member of the TTGlobalFontInfo struct */ + 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 */ + }; + +/** 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 + }; + +/** Structure used by 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 */ + bool compflag; /**< false- if non-composite */ + 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 */ + LanguageType 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_Unicode *ufamily; /**< family name UCS2 */ + char *subfamily; /**< subfamily name */ + sal_Unicode *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: proportional 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 typoAscender; /**< OS/2 portable typographic ascender */ + int typoDescender; /**< OS/2 portable typographic descender */ + int typoLineGap; /**< OS/2 portable typographic line gap */ + int winAscent; /**< ascender metric for Windows */ + int winDescent; /**< descender metric for Windows */ + bool symbolEncoded; /**< true: MS symbol encoded */ + sal_uInt8 panose[10]; /**< PANOSE classification number */ + sal_uInt32 typeFlags; /**< type flags (copyright bits) */ + sal_uInt16 fsSelection; /**< OS/2 fsSelection */ + } TTGlobalFontInfo; + +/** 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; + + struct TrueTypeFont; + +/* + Some table OS/2 consts + quick history: + OpenType has been created from TrueType + - original TrueType had an OS/2 table with a length of 68 bytes + (cf https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html) + - There have been 6 versions (from version 0 to 5) + (cf https://docs.microsoft.com/en-us/typography/opentype/otspec140/os2ver0) + + For the record: + // From Initial TrueType version + TYPE NAME FROM BYTE + uint16 version 0 + int16 xAvgCharWidth 2 + uint16 usWeightClass 4 + uint16 usWidthClass 6 + uint16 fsType 8 + int16 ySubscriptXSize 10 + int16 ySubscriptYSize 12 + int16 ySubscriptXOffset 14 + int16 ySubscriptYOffset 16 + int16 ySuperscriptXSize 18 + int16 ySuperscriptYSize 20 + int16 ySuperscriptXOffset 22 + int16 ySuperscriptYOffset 24 + int16 yStrikeoutSize 26 + int16 yStrikeoutPosition 28 + int16 sFamilyClass 30 + uint8 panose[10] 32 + uint32 ulUnicodeRange1 42 + uint32 ulUnicodeRange2 46 + uint32 ulUnicodeRange3 50 + uint32 ulUnicodeRange4 54 + Tag achVendID 58 + uint16 fsSelection 62 + uint16 usFirstCharIndex 64 + uint16 usLastCharIndex 66 + + // From Version 0 of OpenType + int16 sTypoAscender 68 + int16 sTypoDescender 70 + int16 sTypoLineGap 72 + uint16 usWinAscent 74 + uint16 usWinDescent 76 + + => length for OpenType version 0 = 78 bytes + + // From Version 1 of OpenType + uint32 ulCodePageRange1 78 + uint32 ulCodePageRange2 82 + + => length for OpenType version 1 = 86 bytes + + // From Version 2 of OpenType + // (idem for Versions 3 and 4) + int16 sxHeight 86 + int16 sCapHeight 88 + uint16 usDefaultChar 90 + uint16 usBreakChar 92 + uint16 usMaxContext 94 + + => length for OpenType version 2, 3 and 4 = 96 bytes + + // From Version 5 of OpenType + uint16 usLowerOpticalPointSize 96 + uint16 usUpperOpticalPointSize 98 + END 100 + + => length for OS/2 table version 5 = 100 bytes + +*/ +constexpr int OS2_Legacy_length = 68; +constexpr int OS2_V0_length = 78; +constexpr int OS2_V1_length = 86; + +constexpr int OS2_usWeightClass_offset = 4; +constexpr int OS2_usWidthClass_offset = 6; +constexpr int OS2_fsType_offset = 8; +constexpr int OS2_panose_offset = 32; +constexpr int OS2_panoseNbBytes_offset = 10; +constexpr int OS2_ulUnicodeRange1_offset = 42; +constexpr int OS2_ulUnicodeRange2_offset = 46; +constexpr int OS2_ulUnicodeRange3_offset = 50; +constexpr int OS2_ulUnicodeRange4_offset = 54; +constexpr int OS2_fsSelection_offset = 62; +constexpr int OS2_typoAscender_offset = 68; +constexpr int OS2_typoDescender_offset = 70; +constexpr int OS2_typoLineGap_offset = 72; +constexpr int OS2_winAscent_offset = 74; +constexpr int OS2_winDescent_offset = 76; +constexpr int OS2_ulCodePageRange1_offset = 78; +constexpr int OS2_ulCodePageRange2_offset = 82; + +/* + Some table hhea consts + cf https://docs.microsoft.com/fr-fr/typography/opentype/spec/hhea + TYPE NAME FROM BYTE + uint16 majorVersion 0 + uint16 minorVersion 2 + FWORD ascender 4 + FWORD descender 6 + FWORD lineGap 8 + UFWORD advanceWidthMax 10 + FWORD minLeftSideBearing 12 + FWORD minRightSideBearing 14 + FWORD xMaxExtent 16 + int16 caretSlopeRise 18 + int16 caretSlopeRun 20 + int16 caretOffset 22 + int16 (reserved) 24 + int16 (reserved) 26 + int16 (reserved) 28 + int16 (reserved) 30 + int16 metricDataFormat 32 + uint16 numberOfHMetrics 34 + END 36 + + => length for hhea table = 36 bytes + +*/ +constexpr int HHEA_Length = 36; + +constexpr int HHEA_ascender_offset = 4; +constexpr int HHEA_descender_offset = 6; +constexpr int HHEA_lineGap_offset = 8; +constexpr int HHEA_caretSlopeRise_offset = 18; +constexpr int HHEA_caretSlopeRun_offset = 20; + +/* + Some table post consts + cf https://docs.microsoft.com/fr-fr/typography/opentype/spec/post + TYPE NAME FROM BYTE + Fixed version 0 + Fixed italicAngle 4 + FWord underlinePosition 8 + FWord underlineThickness 10 + uint32 isFixedPitch 12 + ... + +*/ +constexpr int POST_italicAngle_offset = 4; +constexpr int POST_underlinePosition_offset = 8; +constexpr int POST_underlineThickness_offset = 10; +constexpr int POST_isFixedPitch_offset = 12; + +/* + Some table head consts + cf https://docs.microsoft.com/fr-fr/typography/opentype/spec/head + TYPE NAME FROM BYTE + uit16 majorVersion 0 + uit16 minorVersion 2 + Fixed fontRevision 4 + uint32 checkSumAdjustment 8 + uint32 magicNumber 12 (= 0x5F0F3CF5) + uint16 flags 16 + uint16 unitsPerEm 18 + LONGDATETIME created 20 + LONGDATETIME modified 28 + int16 xMin 36 + int16 yMin 38 + int16 xMax 40 + int16 yMax 42 + uint16 macStyle 44 + uint16 lowestRecPPEM 46 + int16 fontDirectionHint 48 + int16 indexToLocFormat 50 + int16 glyphDataFormat 52 + + END 54 + + => length head table = 54 bytes +*/ +constexpr int HEAD_Length = 54; + +constexpr int HEAD_majorVersion_offset = 0; +constexpr int HEAD_fontRevision_offset = 4; +constexpr int HEAD_magicNumber_offset = 12; +constexpr int HEAD_flags_offset = 16; +constexpr int HEAD_unitsPerEm_offset = 18; +constexpr int HEAD_created_offset = 20; +constexpr int HEAD_xMin_offset = 36; +constexpr int HEAD_yMin_offset = 38; +constexpr int HEAD_xMax_offset = 40; +constexpr int HEAD_yMax_offset = 42; +constexpr int HEAD_macStyle_offset = 44; +constexpr int HEAD_lowestRecPPEM_offset = 46; +constexpr int HEAD_fontDirectionHint_offset = 48; +constexpr int HEAD_indexToLocFormat_offset = 50; +constexpr int HEAD_glyphDataFormat_offset = 52; + +/* + Some table maxp consts + cf https://docs.microsoft.com/fr-fr/typography/opentype/spec/maxp + For 0.5 version + TYPE NAME FROM BYTE + Fixed version 0 + uint16 numGlyphs 4 + + For 1.0 Version + Fixed version 0 + uint16 numGlyphs 4 + uint16 maxPoints 6 + uint16 maxContours 8 + uint16 maxCompositePoints 10 + uint16 maxCompositeContours 12 + ... + +*/ +constexpr int MAXP_Version1Length = 32; + +constexpr int MAXP_numGlyphs_offset = 4; +constexpr int MAXP_maxPoints_offset = 6; +constexpr int MAXP_maxContours_offset = 8; +constexpr int MAXP_maxCompositePoints_offset = 10; +constexpr int MAXP_maxCompositeContours_offset = 12; + +/* + Some table glyf consts + cf https://docs.microsoft.com/fr-fr/typography/opentype/spec/glyf + For 0.5 version + TYPE NAME FROM BYTE + int16 numberOfContours 0 + int16 xMin 2 + int16 yMin 4 + int16 xMax 6 + int16 yMax 8 + + END 10 + + => length glyf table = 10 bytes + +*/ +constexpr int GLYF_Length = 10; + +constexpr int GLYF_numberOfContours_offset = 0; +constexpr int GLYF_xMin_offset = 2; +constexpr int GLYF_yMin_offset = 4; +constexpr int GLYF_xMax_offset = 6; +constexpr int GLYF_yMax_offset = 8; + +constexpr sal_uInt32 T_true = 0x74727565; /* 'true' */ +constexpr sal_uInt32 T_ttcf = 0x74746366; /* 'ttcf' */ +constexpr sal_uInt32 T_otto = 0x4f54544f; /* 'OTTO' */ + +// standard TrueType table tags +constexpr sal_uInt32 T_maxp = 0x6D617870; +constexpr sal_uInt32 T_glyf = 0x676C7966; +constexpr sal_uInt32 T_head = 0x68656164; +constexpr sal_uInt32 T_loca = 0x6C6F6361; +constexpr sal_uInt32 T_name = 0x6E616D65; +constexpr sal_uInt32 T_hhea = 0x68686561; +constexpr sal_uInt32 T_hmtx = 0x686D7478; +constexpr sal_uInt32 T_cmap = 0x636D6170; +constexpr sal_uInt32 T_vhea = 0x76686561; +constexpr sal_uInt32 T_vmtx = 0x766D7478; +constexpr sal_uInt32 T_OS2 = 0x4F532F32; +constexpr sal_uInt32 T_post = 0x706F7374; +constexpr sal_uInt32 T_cvt = 0x63767420; +constexpr sal_uInt32 T_prep = 0x70726570; +constexpr sal_uInt32 T_fpgm = 0x6670676D; +constexpr sal_uInt32 T_gsub = 0x47535542; +constexpr sal_uInt32 T_CFF = 0x43464620; + + +/** + * @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 pBuffer - memory buffer + * @param nLen - size of memory buffer + * @param facenum - logical font number within a TTC file. This value is ignored + * for TrueType fonts + * @param ttf - array of TrueTypeFonts + * @return value of SFErrCodes enum + * @ingroup sft + */ + SFErrCodes VCL_DLLPUBLIC OpenTTFontBuffer(const void* pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, TrueTypeFont** ttf); +#if !defined(_WIN32) +/** + * 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 fname - name of TrueType font file + * @param facenum - logical font number within a TTC file. This value is ignored + * for TrueType fonts + * @param ttf - array of TrueTypeFonts + * @return value of SFErrCodes enum + * @ingroup sft + */ + SFErrCodes VCL_DLLPUBLIC OpenTTFontFile(const char *fname, sal_uInt32 facenum, TrueTypeFont** ttf); +#endif + + bool VCL_DLLPUBLIC getTTCoverage( + std::optional> & rUnicodeCoverage, + std::optional> & rCodePageCoverage, + const unsigned char* pTable, size_t nLength); + +/** + * TrueTypeFont destructor. Deallocates the memory. + * @ingroup sft + */ + void VCL_DLLPUBLIC 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 const *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); + +/** + * Generates a new PostScript Type 3 font and dumps it to outf file. + * This function substitutes 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 + * + */ + SFErrCodes CreateT3FromTTGlyphs(TrueTypeFont *ttf, FILE *outf, const char *fname, sal_uInt16 const *glyphArray, sal_uInt8 *encoding, int nGlyphs, int wmode); + +/** + * Generates a new TrueType font and dumps it to outf file. + * This function substitutes 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 flags or'ed TTCreationFlags + * @return return the value of SFErrCodes enum + * @see SFErrCodes + * @ingroup sft + * + */ + VCL_DLLPUBLIC SFErrCodes CreateTTFromTTGlyphs(TrueTypeFont *ttf, + const char *fname, + sal_uInt16 const *glyphArray, + sal_uInt8 const *encoding, + int nGlyphs); + +/** + * Generates a new PostScript Type42 font and dumps it to outf file. + * This function substitutes 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 SFErrCodes::Ok - no errors + * SFErrCodes::GlyphNum - too many glyphs (> 255) + * SFErrCodes::TtFormat - corrupted TrueType fonts + * + * @see SFErrCodes + * @ingroup sft + * + */ + SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, + FILE *outf, + const char *psname, + sal_uInt16 const *glyphArray, + sal_uInt8 *encoding, + int nGlyphs); + +/** + * Queries glyph metrics. Allocates an array of advance width/height values 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 vertical writing mode: false - horizontal, true - vertical + * @ingroup sft + * + */ + VCL_DLLPUBLIC std::unique_ptr GetTTSimpleGlyphMetrics(TrueTypeFont const *ttf, const sal_uInt16 *glyphArray, int nGlyphs, bool vertical); + +#if defined(_WIN32) || defined(MACOSX) || defined(IOS) +/** + * 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 + */ + VCL_DLLPUBLIC sal_uInt16 MapChar(TrueTypeFont const *ttf, sal_uInt16 ch); +#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 + * + */ + VCL_DLLPUBLIC void GetTTGlobalFontInfo(TrueTypeFont *ttf, TTGlobalFontInfo *info); + +/** + * Returns fonts metrics. + * @see TTGlobalFontInfo + * + * @param hhea hhea table data + * @param os2 OS/2 table data + * @param info pointer to a TTGlobalFontInfo structure + * @ingroup sft + * + */ + void GetTTFontMetrics(const uint8_t *pHhea, size_t nHhea, + const uint8_t *pOs2, size_t nOs2, + TTGlobalFontInfo *info); + +/** + * returns the number of glyphs in a font + */ + VCL_DLLPUBLIC int GetTTGlyphCount( TrueTypeFont const * ttf ); + +/** + * provide access to the raw data of a SFNT-container's subtable + */ + bool GetSfntTable( TrueTypeFont const * ttf, int nSubtableIndex, + const sal_uInt8** ppRawBytes, int* pRawLength ); + +/*- private definitions */ + +/* indexes into TrueTypeFont::tables[] and TrueTypeFont::tlens[] */ +constexpr int O_maxp = 0; +constexpr int O_glyf = 1; /* 'glyf' */ +constexpr int O_head = 2; /* 'head' */ +constexpr int O_loca = 3; /* 'loca' */ +constexpr int O_name = 4; /* 'name' */ +constexpr int O_hhea = 5; /* 'hhea' */ +constexpr int O_hmtx = 6; /* 'hmtx' */ +constexpr int O_cmap = 7; /* 'cmap' */ +constexpr int O_vhea = 8; /* 'vhea' */ +constexpr int O_vmtx = 9; /* 'vmtx' */ +constexpr int O_OS2 = 10; /* 'OS/2' */ +constexpr int O_post = 11; /* 'post' */ +constexpr int O_cvt = 12; /* 'cvt_' - only used in TT->TT generation */ +constexpr int O_prep = 13; /* 'prep' - only used in TT->TT generation */ +constexpr int O_fpgm = 14; /* 'fpgm' - only used in TT->TT generation */ +constexpr int O_gsub = 15; /* 'GSUB' */ +constexpr int O_CFF = 16; /* 'CFF' */ +constexpr int NUM_TAGS = 17; + + struct TrueTypeFont { + char *fname; + sal_Int32 fsize; + sal_uInt8 *ptr; + + char *psname; + char *family; + sal_Unicode *ufamily; + char *subfamily; + sal_Unicode *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, sal_uInt32); /* character to glyphID translation function */ + std::array tables; /* array of pointers to raw subtables in SFNT file */ + std::array tlens; /* array of table lengths */ + }; + + +} // namespace vcl + +#endif // INCLUDED_VCL_INC_SFT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx new file mode 100644 index 000000000..ca227e4e8 --- /dev/null +++ b/vcl/inc/skia/gdiimpl.hxx @@ -0,0 +1,332 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SKIA_GDIIMPL_HXX +#define INCLUDED_VCL_SKIA_GDIIMPL_HXX + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +class SkiaFlushIdle; +class GenericSalLayout; +class SkFont; +class SkiaSalBitmap; + +class VCL_DLLPUBLIC SkiaSalGraphicsImpl : public SalGraphicsImpl +{ +public: + SkiaSalGraphicsImpl(SalGraphics& pParent, SalGeometryProvider* pProvider); + virtual ~SkiaSalGraphicsImpl() override; + + virtual void Init() override; + + virtual void DeInit() override; + + virtual OUString getRenderBackendName() const override { return "skia"; } + + const vcl::Region& getClipRegion() const; + virtual bool setClipRegion(const vcl::Region&) override; + + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const override; + + // get the width of the device + virtual long GetGraphicsWidth() const override; + + // set the clip region to empty + virtual void ResetClipRegion() override; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() override; + + // set the line color to a specific color + virtual void SetLineColor(Color nColor) override; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() override; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor(Color nColor) override; + + // enable/disable XOR drawing + virtual void SetXORMode(bool bSet, bool bInvertOnly) override; + + // set line color for raster operations + virtual void SetROPLineColor(SalROPColor nROPColor) override; + + // set fill color for raster operations + virtual void SetROPFillColor(SalROPColor nROPColor) override; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel(long nX, long nY) override; + virtual void drawPixel(long nX, long nY, Color nColor) override; + + virtual void drawLine(long nX1, long nY1, long nX2, long nY2) override; + + virtual void drawRect(long nX, long nY, long nWidth, long nHeight) override; + + virtual void drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) override; + + virtual void drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) override; + + virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry) override; + + virtual bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, double fTransparency) override; + + virtual bool drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, double fTransparency, double fLineWidth, + const std::vector* pStroke, basegfx::B2DLineJoin, + css::drawing::LineCap, double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + + virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, + const PolyFlags* pFlgAry) override; + + virtual bool drawPolygonBezier(sal_uInt32 nPoints, const SalPoint* pPtAry, + const PolyFlags* pFlgAry) override; + + virtual bool drawPolyPolygonBezier(sal_uInt32 nPoly, const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry) override; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool bWindowInvalidate) override; + + virtual void copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) override; + + virtual bool blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap) override; + + virtual bool blendAlphaBitmap(const SalTwoRect&, const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap) override; + + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) override; + + virtual void drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap) override; + + virtual void drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + Color nMaskColor) override; + + virtual std::shared_ptr getBitmap(long nX, long nY, long nWidth, + long nHeight) override; + + virtual Color getPixel(long nX, long nY) override; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert(long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) override; + + virtual void invert(sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags) override; + + virtual bool drawEPS(long nX, long nY, long nWidth, long nHeight, void* pPtr, + sal_uInt32 nSize) override; + + /** 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) override; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + + /** Render solid rectangle with given transparency + + @param nX Top left coordinate of rectangle + + @param nY Bottom right coordinate of rectangle + + @param nWidth Width of rectangle + + @param nHeight Height of rectangle + + @param nTransparency Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + + @returns true if successfully drawn, false if not able to draw rectangle + */ + virtual bool drawAlphaRect(long nX, long nY, long nWidth, long nHeight, + sal_uInt8 nTransparency) override; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, + const Gradient& rGradient) override; + + virtual bool supportsOperation(OutDevSupportType eType) const override; + +#ifdef DBG_UTIL + void dump(const char* file) const; +#endif + + // Default blend mode for SkPaint is SkBlendMode::kSrcOver + void drawImage(const SalTwoRect& rPosAry, const sk_sp& aImage, + SkBlendMode eBlendMode = SkBlendMode::kSrcOver); + + void drawShader(const SalTwoRect& rPosAry, const sk_sp& shader); + + enum class GlyphOrientation + { + Apply, + Ignore + }; + void drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font, + GlyphOrientation glyphOrientation); + +protected: + // To be called before any drawing. + void preDraw(); + // To be called after any drawing. + void postDraw(); + // The canvas to draw to. Will be diverted to a temporary for Xor mode. + SkCanvas* getDrawCanvas() { return mXorMode ? getXorCanvas() : mSurface->getCanvas(); } + // Call before makeImageSnapshot(), ensures the content is up to date. + void flushDrawing(); + + virtual void createSurface(); + // Call to ensure that mSurface is valid. If mSurface is going to be modified, + // use preDraw() instead of this. + void checkSurface(); + void destroySurface(); + // Reimplemented for X11. + virtual bool avoidRecreateByResize() const { return false; } + void createWindowSurface(bool forceRaster = false); + virtual void createWindowContext(bool forceRaster = false) = 0; + void createOffscreenSurface(); + + void privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, double nTransparency, + bool blockAA = false); + + void setProvider(SalGeometryProvider* provider) { mProvider = provider; } + + bool isOffscreen() const { return mProvider == nullptr || mProvider->IsOffScreen(); } + bool isGPU() const { return mIsGPU; } + + void invert(basegfx::B2DPolygon const& rPoly, SalInvert eFlags); + + // Called by SkiaFlushIdle. + virtual void performFlush() = 0; + void scheduleFlush(); + friend class SkiaFlushIdle; + + // get the width of the device + int GetWidth() const { return mProvider ? mProvider->GetWidth() : 1; } + // get the height of the device + int GetHeight() const { return mProvider ? mProvider->GetHeight() : 1; } + + SkCanvas* getXorCanvas(); + void applyXor(); + // NOTE: This must be called before the operation does any drawing. + void addXorRegion(const SkRect& rect) + { + if (mXorMode) + { + // Make slightly larger, just in case (rounding, antialiasing,...). + SkIRect addedRect = rect.makeOutset(2, 2).round(); + // Two xor operations should cancel each other out. We batch xor operations, + // but if they can overlap, apply xor now, since applyXor() does the operation + // just once. + if (mXorRegion.intersects(addedRect)) + applyXor(); + mXorRegion.op(addedRect, SkRegion::kUnion_Op); + } + } + static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region); + sk_sp mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap, + const Size targetSize); + + // Skia uses floating point coordinates, so when we use integer coordinates, sometimes + // rounding results in off-by-one errors (down), especially when drawing using GPU, + // see https://bugs.chromium.org/p/skia/issues/detail?id=9611 . Compensate for + // it by using centers of pixels. Using 0.5 may sometimes round up, so go with 0.495 . + static constexpr SkScalar toSkX(long x) { return x + 0.495; } + static constexpr SkScalar toSkY(long y) { return y + 0.495; } + // Value to add to be exactly in the middle of the pixel. + static constexpr SkScalar toSkXYFix = SkScalar(0.005); + + // Perform any pending drawing such as delayed merging of polygons. Called by preDraw() + // and anything that means the next operation cannot be another one in a series (e.g. + // changing colors). + void checkPendingDrawing(); + bool delayDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency); + void performDrawPolyPolygon(const basegfx::B2DPolyPolygon& polygon, double transparency, + bool useAA); + + template + friend inline std::basic_ostream& + operator<<(std::basic_ostream& stream, const SkiaSalGraphicsImpl* graphics) + { // O - offscreen, G - GPU-based, R - raster + return stream << static_cast(graphics) << " " + << Size(graphics->GetWidth(), graphics->GetHeight()) + << (graphics->isGPU() ? "G" : "R") << (graphics->isOffscreen() ? "O" : ""); + } + + SalGraphics& mParent; + /// Pointer to the SalFrame or SalVirtualDevice + SalGeometryProvider* mProvider; + std::unique_ptr mWindowContext; + // The Skia surface that is target of all the rendering. + sk_sp mSurface; + bool mIsGPU; // whether the surface is GPU-backed + // Keep reference to shared GrContext. + vcl::Region mClipRegion; + Color mLineColor; + Color mFillColor; + bool mXorMode; + SkBitmap mXorBitmap; + std::unique_ptr mXorCanvas; + SkRegion mXorRegion; // the area that needs updating for the xor operation + std::unique_ptr mFlush; + // Info about pending polygons to draw (we try to merge adjacent polygons into one). + struct LastPolyPolygonInfo + { + basegfx::B2DPolyPolygonVector polygons; + basegfx::B2DRange bounds; + double transparency; + }; + LastPolyPolygonInfo mLastPolyPolygonInfo; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx new file mode 100644 index 000000000..5079be088 --- /dev/null +++ b/vcl/inc/skia/salbmp.hxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_SALBMP_H +#define INCLUDED_VCL_INC_SKIA_SALBMP_H + +#include + +#include + +#include + +class VCL_PLUGIN_PUBLIC SkiaSalBitmap final : public SalBitmap +{ +public: + SkiaSalBitmap(); + SkiaSalBitmap(const sk_sp& image); + virtual ~SkiaSalBitmap() override; + + // SalBitmap methods + virtual bool Create(const Size& rSize, sal_uInt16 nBitCount, + const BitmapPalette& rPal) override; + virtual bool Create(const SalBitmap& rSalBmp) override; + virtual bool Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) override; + virtual bool Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount) override; + virtual bool Create(const css::uno::Reference& rBitmapCanvas, + Size& rSize, bool bMask = false) override; + + virtual void Destroy() final override; + + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer(BitmapAccessMode nMode) override; + virtual void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) override; + + virtual bool GetSystemData(BitmapSystemData& rData) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale(const double& rScaleX, const double& rScaleY, + BmpScaleFlag nScaleFlag) override; + virtual bool Replace(const Color& rSearchColor, const Color& rReplaceColor, + sal_uInt8 nTol) override; + virtual bool InterpretAs8Bit() override; + virtual bool ConvertToGreyscale() override; + + const BitmapPalette& Palette() const { return mPalette; } + // Returns the contents as SkImage (possibly GPU-backed). + const sk_sp& GetSkImage() const; + + // Returns the contents as alpha SkImage (possibly GPU-backed) + const sk_sp& GetAlphaSkImage() const; + +#ifdef DBG_UTIL + void dump(const char* file) const; +#endif + +private: + // Reset the cached images allocated in GetSkImage()/GetAlphaSkImage(). + void ResetCachedData(); + // Sets the data only as SkImage (will be converted as needed). + void ResetToSkImage(sk_sp image); + // Resets all data that does not match mSize. + void ResetCachedDataBySize(); + // Call to ensure mBuffer has data (will convert from mImage if necessary). + void EnsureBitmapData(); + void EnsureBitmapData() const { return const_cast(this)->EnsureBitmapData(); } + // Like EnsureBitmapData(), but will also make any shared data unique. + // Call before changing the data. + void EnsureBitmapUniqueData(); + // Allocate mBuffer (with uninitialized contents). + bool CreateBitmapData(); + SkBitmap GetAsSkBitmap() const; +#ifdef DBG_UTIL + void verify() const; +#else + void verify() const {}; +#endif + + template + friend inline std::basic_ostream& + operator<<(std::basic_ostream& stream, const SkiaSalBitmap* bitmap) + { + // I/i - has SkImage (on GPU/CPU), + // A/a - has alpha SkImage (on GPU/CPU) + return stream << static_cast(bitmap) << " " << bitmap->GetSize() << "/" + << (bitmap->mImage ? (bitmap->mImage->isTextureBacked() ? "I" : "i") : "") + << (bitmap->mAlphaImage ? (bitmap->mAlphaImage->isTextureBacked() ? "A" : "a") + : ""); + } + + BitmapPalette mPalette; + int mBitCount = 0; // bpp + Size mSize; + // The contents of the bitmap may be stored in several different ways: + // As mBuffer buffer, which normally stores pixels in the given format. + // As SkImage, as cached GPU-backed data, but sometimes also a result of some operation. + // There is no "master" storage that the other would be derived from. The usual + // mode of operation is that mBuffer holds the data, mImage is created + // on demand as GPU-backed cached data by calling GetSkImage(), and the cached mImage + // is reset by ResetCachedImage(). But sometimes only mImage will be set and in that case + // mBuffer must be filled from it on demand if necessary by EnsureBitmapData(). + boost::shared_ptr mBuffer; + int mScanlineSize; // size of one row in mBuffer + sk_sp mImage; // possibly GPU-backed + sk_sp mAlphaImage; // cached contents as alpha image, possibly GPU-backed + // Actual scaling triggered by scale() is done on-demand. This is the size of the pixel + // data in mBuffer, if it differs from mSize, then there is a scaling operation pending. + Size mPixelsSize; + SkFilterQuality mScaleQuality = kHigh_SkFilterQuality; // quality for on-demand scaling +#ifdef DBG_UTIL + int mWriteAccessCount = 0; // number of write AcquireAccess() that have not been released +#endif +}; + +#endif // INCLUDED_VCL_INC_SKIA_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx new file mode 100644 index 000000000..a43ff8f58 --- /dev/null +++ b/vcl/inc/skia/utils.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_UTILS_H +#define INCLUDED_VCL_INC_SKIA_UTILS_H + +#include + +#include +#include + +#include +#include + +namespace SkiaHelper +{ +// Get the one shared GrContext instance. +GrContext* getSharedGrContext(); + +void disableRenderMethod(RenderMethod method); + +// Create SkSurface, GPU-backed if possible. +VCL_DLLPUBLIC sk_sp createSkSurface(int width, int height, + SkColorType type = kN32_SkColorType); + +inline sk_sp createSkSurface(const Size& size, SkColorType type = kN32_SkColorType) +{ + return createSkSurface(size.Width(), size.Height(), type); +} + +// Create SkImage, GPU-backed if possible. +VCL_DLLPUBLIC sk_sp createSkImage(const SkBitmap& bitmap); + +// Call surface->makeImageSnapshot() and abort on failure. +VCL_DLLPUBLIC sk_sp makeCheckedImageSnapshot(sk_sp surface); +VCL_DLLPUBLIC sk_sp makeCheckedImageSnapshot(sk_sp surface, + const SkIRect& bounds); + +// Must be called in any VCL backend before any Skia functionality is used. +// If not set, Skia will be disabled. +VCL_DLLPUBLIC void + prepareSkia(std::unique_ptr (*createVulkanWindowContext)(bool)); + +// Shared cache of images. +void addCachedImage(const OString& key, sk_sp image); +sk_sp findCachedImage(const OString& key); +void removeCachedImage(sk_sp image); + +#ifdef DBG_UTIL +void prefillSurface(sk_sp& surface); +VCL_DLLPUBLIC void dump(const SkBitmap& bitmap, const char* file); +VCL_DLLPUBLIC void dump(const sk_sp& image, const char* file); +VCL_DLLPUBLIC void dump(const sk_sp& surface, const char* file); +#endif + +extern uint32_t vendorId; + +inline DriverBlocklist::DeviceVendor getVendor() +{ + return DriverBlocklist::GetVendorFromId(vendorId); +} + +} // namespace + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const SkRect& rectangle) +{ + if (rectangle.isEmpty()) + return stream << "EMPTY"; + else + return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x() + << ',' << rectangle.y() << ")"; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const SkIRect& rectangle) +{ + if (rectangle.isEmpty()) + return stream << "EMPTY"; + else + return stream << rectangle.width() << 'x' << rectangle.height() << "@(" << rectangle.x() + << ',' << rectangle.y() << ")"; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const SkRegion& region) +{ + if (region.isEmpty()) + return stream << "EMPTY"; + stream << "("; + SkRegion::Iterator it(region); + for (int i = 0; !it.done(); it.next(), ++i) + stream << "[" << i << "] " << it.rect(); + stream << ")"; + return stream; +} + +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const SkImage& image) +{ + // G - on GPU + return stream << static_cast(&image) << " " << Size(image.width(), image.height()) + << "/" << (SkColorTypeBytesPerPixel(image.imageInfo().colorType()) * 8) + << (image.isTextureBacked() ? "G" : ""); +} +template +inline std::basic_ostream& operator<<(std::basic_ostream& stream, + const sk_sp& image) +{ + return stream << *image; +} + +#endif // INCLUDED_VCL_INC_SKIA_UTILS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx new file mode 100644 index 000000000..564fcd7e9 --- /dev/null +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_WIN_GDIIMPL_HXX +#define INCLUDED_VCL_INC_SKIA_WIN_GDIIMPL_HXX + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +class SkTypeface; +class SkFontMgr; +class ControlCacheKey; + +class SkiaCompatibleDC : public CompatibleDC +{ +public: + SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height); + + virtual std::unique_ptr getAsMaskTexture() const override; + + sk_sp getAsImage() const; + sk_sp getAsMaskImage() const; + sk_sp getAsImageDiff(const SkiaCompatibleDC& white) const; + + struct Texture; +}; + +struct SkiaCompatibleDC::Texture : public CompatibleDC::Texture +{ + sk_sp image; + virtual bool isValid() const { return image.get(); } + virtual int GetWidth() const { return image->width(); } + virtual int GetHeight() const { return image->height(); } +}; + +class WinSkiaSalGraphicsImpl : public SkiaSalGraphicsImpl, public WinSalGraphicsImplBase +{ +private: + WinSalGraphics& mWinParent; + +public: + WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics, SalGeometryProvider* mpProvider); + + virtual void DeInit() override; + virtual void freeResources() override; + + virtual bool UseRenderNativeControl() const override { return true; } + virtual bool TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, int nX, + int nY) override; + virtual bool RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, int nX, + int nY, ControlCacheKey& aControlCacheKey) override; + + virtual bool DrawTextLayout(const GenericSalLayout& layout) override; + virtual void ClearDevFontCache() override; + + static void prepareSkia(); + +protected: + virtual void createWindowContext(bool forceRaster = false) override; + virtual void performFlush() override; + sk_sp createDirectWriteTypeface(const LOGFONTW& logFont); + SkFont::Edging getFontEdging(); + IDWriteFactory* dwriteFactory; + IDWriteGdiInterop* dwriteGdiInterop; + sk_sp dwriteFontMgr; + bool dwriteDone = false; + SkFont::Edging fontEdging; + bool fontEdgingDone = false; +}; + +typedef std::pair> SkiaControlCachePair; +typedef o3tl::lru_map, ControlCacheHashFunction> + SkiaControlCacheType; + +class SkiaControlsCache +{ + SkiaControlCacheType cache; + + SkiaControlsCache(); + +public: + static SkiaControlCacheType& get(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx new file mode 100644 index 000000000..d131d54bf --- /dev/null +++ b/vcl/inc/skia/x11/gdiimpl.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX +#define INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX + +#include + +#include +#include +#include +#include + +class VCL_PLUGIN_PUBLIC X11SkiaSalGraphicsImpl final : public SkiaSalGraphicsImpl, + public X11GraphicsImpl +{ +private: + X11SalGraphics& mX11Parent; + +public: + X11SkiaSalGraphicsImpl(X11SalGraphics& rParent); + virtual ~X11SkiaSalGraphicsImpl() override; + + virtual void Init() override; + virtual void DeInit() override; + virtual void freeResources() override; + + static void prepareSkia(); + +private: + virtual void createWindowContext(bool forceRaster = false) override; + virtual void performFlush() override; + virtual bool avoidRecreateByResize() const override; + static std::unique_ptr + createWindowContext(Display* display, Drawable drawable, const XVisualInfo* visual, int width, + int height, SkiaHelper::RenderMethod renderMethod, bool temporary); + friend std::unique_ptr createVulkanWindowContext(bool); +}; + +#endif // INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/salvd.hxx b/vcl/inc/skia/x11/salvd.hxx new file mode 100644 index 000000000..8ff75175d --- /dev/null +++ b/vcl/inc/skia/x11/salvd.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_X11_SALVD_H +#define INCLUDED_VCL_INC_SKIA_X11_SALVD_H + +#include + +class X11SkiaSalVirtualDevice : public SalVirtualDevice +{ + SalDisplay* mpDisplay; + std::unique_ptr mpGraphics; + bool mbGraphics; // is Graphics used + SalX11Screen mnXScreen; + int mnWidth; + int mnHeight; + +public: + X11SkiaSalVirtualDevice(SalGraphics const* pGraphics, long nDX, long nDY, + const SystemGraphicsData* pData, + std::unique_ptr pNewGraphics); + virtual ~X11SkiaSalVirtualDevice() override; + + // SalGeometryProvider + virtual long GetWidth() const override { return mnWidth; } + virtual long GetHeight() const override { return mnHeight; } + + SalDisplay* GetDisplay() const { return mpDisplay; } + const SalX11Screen& GetXScreenNumber() const { return mnXScreen; } + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics(SalGraphics* pGraphics) override; + + // Set new size, without saving the old contents + virtual bool SetSize(long nNewDX, long nNewDY) override; +}; + +#endif // INCLUDED_VCL_INC_SKIA_X11_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/x11/textrender.hxx b/vcl/inc/skia/x11/textrender.hxx new file mode 100644 index 000000000..d6eda9a04 --- /dev/null +++ b/vcl/inc/skia/x11/textrender.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SKIA_TEXTRENDER_HXX +#define INCLUDED_VCL_INC_SKIA_TEXTRENDER_HXX + +#include + +#include +#include + +class VCL_DLLPUBLIC SkiaTextRender final : public FreeTypeTextRenderImpl +{ +public: + virtual void DrawTextLayout(const GenericSalLayout&, const SalGraphics&) override; + virtual void ClearDevFontCache() override; + +private: + sk_sp fontManager; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/skia/zone.hxx b/vcl/inc/skia/zone.hxx new file mode 100644 index 000000000..1f6bbb0dd --- /dev/null +++ b/vcl/inc/skia/zone.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_SKIA_ZONE_H +#define INCLUDED_VCL_INC_SKIA_ZONE_H + +#include + +#include + +// Used around calls to Skia code to detect crashes in drivers. +class VCL_DLLPUBLIC SkiaZone : public CrashZone +{ +public: + static void hardDisable(); + static void relaxWatchdogTimings(); + static const CrashWatchdogTimingsValues& getCrashWatchdogTimingsValues(); + static void checkDebug(int nUnchanged, const CrashWatchdogTimingsValues& aTimingValues); + static const char* name() { return "Skia"; } +}; + +#endif // INCLUDED_VCL_INC_SKIA_ZONE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/slider.hxx b/vcl/inc/slider.hxx new file mode 100644 index 000000000..6f57d269c --- /dev/null +++ b/vcl/inc/slider.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SLIDER_HXX +#define INCLUDED_VCL_SLIDER_HXX + +#include +#include +#include + +class Slider final : public Control +{ +private: + tools::Rectangle maChannel1Rect; + tools::Rectangle maChannel2Rect; + tools::Rectangle maThumbRect; + long mnStartPos; + long mnMouseOff; + long mnThumbPixOffset; + long mnThumbPixRange; + long mnThumbPixPos; + long mnThumbSize; + long mnChannelPixRange; + long mnChannelPixTop; + long mnChannelPixBottom; + long mnMinRange; + long mnMaxRange; + long mnThumbPos; + long mnLineSize; + long mnPageSize; + sal_uInt16 mnStateFlags; + ScrollType meScrollType; + bool mbCalcSize; + + Link maSlideHdl; + + using Control::ImplInitSettings; + using Window::ImplInit; + void ImplInit( vcl::Window* pParent, WinBits nStyle ); + void ImplInitSettings(); + void ImplUpdateRects( bool bUpdate = true ); + long ImplCalcThumbPos( long nPixPos ); + long ImplCalcThumbPosPix( long nPos ); + void ImplCalc( bool bUpdate = true ); + void ImplDraw(vcl::RenderContext& rRenderContext); + bool ImplIsPageUp( const Point& rPos ); + bool ImplIsPageDown( const Point& rPos ); + long ImplSlide( long nNewPos ); + long ImplDoAction( ); + void ImplDoMouseAction( const Point& rPos, bool bCallAction ); + void ImplDoSlide( long nNewPos ); + void ImplDoSlideAction( ScrollType eScrollType ); + +public: + Slider( vcl::Window* pParent, WinBits nStyle); + virtual ~Slider() override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void Tracking( const TrackingEvent& rTEvt ) override; + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void Resize() override; + virtual void StateChanged( StateChangedType nType ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + + void Slide(); + + void SetRangeMin(long nNewRange); + long GetRangeMin() const { return mnMinRange; } + void SetRangeMax(long nNewRange); + long GetRangeMax() const { return mnMaxRange; } + void SetRange( const Range& rRange ); + 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; } + + Size CalcWindowSizePixel(); + + void SetSlideHdl( const Link& rLink ) { maSlideHdl = rLink; } +}; + +#endif // INCLUDED_VCL_SLIDER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/spin.hxx b/vcl/inc/spin.hxx new file mode 100644 index 000000000..7b7fbe11b --- /dev/null +++ b/vcl/inc/spin.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SPIN_HXX +#define INCLUDED_VCL_INC_SPIN_HXX + +#include + +namespace tools { class Rectangle; } + +// Draw Spinners as found in a SpinButton. Some themes like gtk3 will draw +- elements here, +// so these are only suitable in the context of SpinButtons +void ImplDrawSpinButton(vcl::RenderContext& rRenderContext, vcl::Window* pWindow, + const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect, + bool bUpperIn, bool bLowerIn, bool bUpperEnabled = true, bool bLowerEnabled = true, + bool bHorz = false, bool bMirrorHorz = false); + +// Draw Up/Down buttons suitable for use in any context +void ImplDrawUpDownButtons(vcl::RenderContext& rRenderContext, + const tools::Rectangle& rUpperRect, const tools::Rectangle& rLowerRect, + bool bUpperIn, bool bLowerIn, bool bUpperEnabled, bool bLowerEnabled, + bool bHorz, bool bMirrorHorz = false); + + +#endif // INCLUDED_VCL_INC_SPIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/strhelper.hxx b/vcl/inc/strhelper.hxx new file mode 100644 index 000000000..be2f54678 --- /dev/null +++ b/vcl/inc/strhelper.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_STRHELPER_HXX +#define INCLUDED_VCL_STRHELPER_HXX + +#include +#include +#include +#include + +namespace psp +{ + OUString GetCommandLineToken( int, const OUString& ); + OString GetCommandLineToken(int, const OString&); + // gets one token of a unix command line style string + // doublequote, singlequote and singleleftquote protect their respective + // contents + + int GetCommandLineTokenCount(const OUString&); + // returns number of tokens (zero if empty or whitespace only) + + OUString WhitespaceToSpace( const OUString&, bool bProtect = true ); + OString WhitespaceToSpace(const OString&); + // returns a string with multiple adjacent occurrences of whitespace + // converted to a single space. if bProtect is sal_True (nonzero), then + // doublequote, singlequote and singleleftquote protect their respective + // contents + + + // parses the first double in the string; decimal is '.' only + inline double StringToDouble( const OUString& rStr ) + { + return rtl::math::stringToDouble(rStr, u'.', u'\0'); + } + + inline double StringToDouble(const OString& rStr) + { + return rtl::math::stringToDouble(rStr, '.', static_cast(0)); + } + + // 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 getValueOfDouble( char* pBuffer, double f, int nPrecision = 0) + { + 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 // INCLUDED_VCL_STRHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc new file mode 100644 index 000000000..e378b5481 --- /dev/null +++ b/vcl/inc/strings.hrc @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_STRINGS_HRC +#define INCLUDED_VCL_INC_STRINGS_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +#define SV_RESID_STRING_NOSELECTIONPOSSIBLE NC_("SV_RESID_STRING_NOSELECTIONPOSSIBLE", "") + +#define SV_MENU_MAC_SERVICES NC_("SV_MENU_MAC_SERVICES", "Services") +#define SV_MENU_MAC_HIDEAPP NC_("SV_MENU_MAC_HIDEAPP", "Hide %PRODUCTNAME") +#define SV_MENU_MAC_HIDEALL NC_("SV_MENU_MAC_HIDEALL", "Hide Others") +#define SV_MENU_MAC_SHOWALL NC_("SV_MENU_MAC_SHOWALL", "Show All") +#define SV_MENU_MAC_QUITAPP NC_("SV_MENU_MAC_QUITAPP", "Quit %PRODUCTNAME") + +#define SV_HELPTEXT_CLOSE NC_("SV_HELPTEXT_CLOSE", "Close") +#define SV_HELPTEXT_MINIMIZE NC_("SV_HELPTEXT_MINIMIZE", "Minimize") +#define SV_HELPTEXT_MAXIMIZE NC_("SV_HELPTEXT_MAXIMIZE", "Maximize") +#define SV_HELPTEXT_RESTORE NC_("SV_HELPTEXT_RESTORE", "Restore") +#define SV_HELPTEXT_ROLLDOWN NC_("SV_HELPTEXT_ROLLDOWN", "Drop down") +#define SV_HELPTEXT_ROLLUP NC_("SV_HELPTEXT_ROLLUP", "Roll up") +#define SV_HELPTEXT_HELP NC_("SV_HELPTEXT_HELP", "Help") +#define SV_HELPTEXT_SCREENSHOT NC_("SV_HELPTEXT_SCREENSHOT", "Take and annotate a screenshot") +#define SV_HELPTEXT_FADEIN NC_("SV_HELPTEXT_FADEIN", "Show") +#define SV_HELPTEXT_FADEOUT NC_("SV_HELPTEXT_FADEOUT", "Hide") +#define SV_HELPTEXT_CLOSEDOCUMENT NC_("SV_HELPTEXT_CLOSEDOCUMENT", "Close Document") + +// To translators: This is used on buttons for platforms other than Windows, there should be a ~ mnemonic in this string +#define SV_BUTTONTEXT_OK NC_("SV_BUTTONTEXT_OK", "~OK") +// To translators: This is used on buttons for platforms other than windows, there should be a ~ mnemonic in this string +#define SV_BUTTONTEXT_CANCEL NC_("SV_BUTTONTEXT_CANCEL", "~Cancel") +// To translators: This is used on buttons for Windows, there should be no ~ mnemonic in this string +#define SV_BUTTONTEXT_OK_NOMNEMONIC NC_("SV_BUTTONTEXT_OK_NOMNEMONIC", "OK") +// To translators: This is used on buttons for Windows, there should be no ~ mnemonic in this string +#define SV_BUTTONTEXT_CANCEL_NOMNEMONIC NC_("SV_BUTTONTEXT_CANCEL_NOMNEMONIC", "Cancel") +#define SV_BUTTONTEXT_YES NC_("SV_BUTTONTEXT_YES", "~Yes") +#define SV_BUTTONTEXT_NO NC_("SV_BUTTONTEXT_NO", "~No") +#define SV_BUTTONTEXT_RETRY NC_("SV_BUTTONTEXT_RETRY", "~Retry") +#define SV_BUTTONTEXT_HELP NC_("SV_BUTTONTEXT_HELP", "~Help") +#define SV_BUTTONTEXT_CLOSE NC_("SV_BUTTONTEXT_CLOSE", "~Close") +#define SV_BUTTONTEXT_MORE NC_("SV_BUTTONTEXT_MORE", "~More") +#define SV_BUTTONTEXT_IGNORE NC_("SV_BUTTONTEXT_IGNORE", "~Ignore") +#define SV_BUTTONTEXT_ABORT NC_("SV_BUTTONTEXT_ABORT", "~Abort") +#define SV_BUTTONTEXT_LESS NC_("SV_BUTTONTEXT_LESS", "~Less") +#define SV_BUTTONTEXT_RESET NC_("SV_BUTTONTEXT_RESET", "R~eset") +#define SV_BUTTONTEXT_ADD NC_("SV_BUTTONTEXT_ADD", "~Add") +#define SV_BUTTONTEXT_DELETE NC_("SV_BUTTONTEXT_DELETE", "~Delete") +#define SV_BUTTONTEXT_REMOVE NC_("SV_BUTTONTEXT_REMOVE", "~Remove") +#define SV_BUTTONTEXT_NEW NC_("SV_BUTTONTEXT_NEW", "~New") +#define SV_BUTTONTEXT_EDIT NC_("SV_BUTTONTEXT_EDIT", "~Edit") +#define SV_BUTTONTEXT_APPLY NC_("SV_BUTTONTEXT_APPLY", "~Apply") +#define SV_BUTTONTEXT_SAVE NC_("SV_BUTTONTEXT_SAVE", "~Save") +#define SV_BUTTONTEXT_UNDO NC_("SV_BUTTONTEXT_UNDO", "~Undo") +#define SV_BUTTONTEXT_PASTE NC_("SV_BUTTONTEXT_PASTE", "~Paste") +#define SV_BUTTONTEXT_NEXT NC_("SV_BUTTONTEXT_NEXT", "~Next") +#define SV_BUTTONTEXT_PREV NC_("SV_BUTTONTEXT_PREV", "~Previous") +#define SV_BUTTONTEXT_GO_UP NC_("SV_BUTTONTEXT_GO_UP", "~Up") +#define SV_BUTTONTEXT_GO_DOWN NC_("SV_BUTTONTEXT_GO_DOWN", "Do~wn") +#define SV_BUTTONTEXT_CLEAR NC_("SV_BUTTONTEXT_CLEAR", "~Clear") +#define SV_BUTTONTEXT_OPEN NC_("SV_BUTTONTEXT_OPEN", "~Open") +#define SV_BUTTONTEXT_PLAY NC_("SV_BUTTONTEXT_PLAY", "~Play") +#define SV_BUTTONTEXT_FIND NC_("SV_BUTTONTEXT_FIND", "~Find") +#define SV_BUTTONTEXT_STOP NC_("SV_BUTTONTEXT_STOP", "~Stop") +#define SV_BUTTONTEXT_CONNECT NC_("SV_BUTTONTEXT_CONNECT", "C~onnect") +#define SV_BUTTONTEXT_SCREENSHOT NC_("SV_BUTTONTEXT_SCREENSHOT", "~Screenshot") + +#define SV_STDTEXT_SERVICENOTAVAILABLE NC_("SV_STDTEXT_SERVICENOTAVAILABLE", "The component (%s) could not be loaded.\nPlease start setup with the repair option.") + +#define SV_STDTEXT_ABOUT NC_("SV_STDTEXT_ABOUT", "About %PRODUCTNAME") +#define SV_STDTEXT_PREFERENCES NC_("SV_STDTEXT_PREFERENCES", "Preferences...") +#define SV_STDTEXT_ALLFILETYPES NC_("SV_STDTEXT_ALLFILETYPES", "Any type") + +#define STR_FPICKER_AUTO_EXTENSION NC_("STR_FPICKER_AUTO_EXTENSION", "~Automatic file name extension") +#define STR_FPICKER_PASSWORD NC_("STR_FPICKER_PASSWORD", "Save with pass~word") +// dear loplugins, please don't remove this constant, it will be used in follow-up commits +#define STR_FPICKER_GPGENCRYPT NC_("STR_FPICKER_GPGENCRYPT", "Encrypt with ~GPG key") +#define STR_FPICKER_FILTER_OPTIONS NC_("STR_FPICKER_FILTER_OPTIONS", "~Edit filter settings") +#define STR_FPICKER_READONLY NC_("STR_FPICKER_READONLY", "~Read-only") +#define STR_FPICKER_INSERT_AS_LINK NC_("STR_FPICKER_INSERT_AS_LINK", "Insert as ~Link") +#define STR_FPICKER_SHOW_PREVIEW NC_("STR_FPICKER_SHOW_PREVIEW", "Pr~eview") +#define STR_FPICKER_PLAY NC_("STR_FPICKER_PLAY", "~Play") +#define STR_FPICKER_VERSION NC_("STR_FPICKER_VERSION", "~Version:") +#define STR_FPICKER_TEMPLATES NC_("STR_FPICKER_TEMPLATES", "S~tyles:") +#define STR_FPICKER_IMAGE_TEMPLATE NC_("STR_FPICKER_IMAGE_TEMPLATE", "Frame Style: ") +#define STR_FPICKER_IMAGE_ANCHOR NC_("STR_FPICKER_IMAGE_ANCHOR", "A~nchor: ") +#define STR_FPICKER_SELECTION NC_("STR_FPICKER_SELECTION", "~Selection") +#define STR_FPICKER_FOLDER_DEFAULT_TITLE NC_("STR_FPICKER_FOLDER_DEFAULT_TITLE", "Select Path") +#define STR_FPICKER_FOLDER_DEFAULT_DESCRIPTION NC_("STR_FPICKER_FOLDER_DEFAULT_DESCRIPTION", "Please select a folder.") +#define STR_FPICKER_ALREADYEXISTOVERWRITE_PRIMARY NC_("STR_FPICKER_ALREADYEXISTOVERWRITE_PRIMARY", "A file named \"$filename$\" already exists. Do you want to replace it?") +#define STR_FPICKER_ALREADYEXISTOVERWRITE_SECONDARY NC_("STR_FPICKER_ALREADYEXISTOVERWRITE_SECONDARY", "The file already exists in \"$dirname$\". Replacing it will overwrite its contents.") +#define STR_FPICKER_ALLFORMATS NC_("STR_FPICKER_ALLFORMATS", "All Formats") +#define STR_FPICKER_OPEN NC_("STR_FPICKER_OPEN", "Open") +#define STR_FPICKER_SAVE NC_("STR_FPICKER_SAVE", "Save") +#define STR_FPICKER_TYPE NC_("STR_FPICKER_TYPE", "File ~type") + +#define SV_ACCESSERROR_NO_FONTS NC_("SV_ACCESSERROR_NO_FONTS", "No fonts could be found on the system.") + +#define SV_PRINT_NOPAGES NC_("SV_PRINT_NOPAGES", "No pages") +#define SV_PRINT_NOPREVIEW NC_("SV_PRINT_NOPREVIEW", "Preview is disabled") +#define SV_PRINT_TOFILE_TXT NC_("SV_PRINT_TOFILE_TXT", "Print to File...") +#define SV_PRINT_DEFPRT_TXT NC_("SV_PRINT_DEFPRT_TXT", "Default printer") +#define SV_PRINT_QUERYFAXNUMBER_TXT NC_("SV_PRINT_QUERYFAXNUMBER_TXT", "Please enter the fax number") +#define SV_PRINT_CUSTOM_TXT NC_("SV_PRINT_CUSTOM_TXT", "Custom") + +#define SV_EDIT_WARNING_STR NC_("SV_EDIT_WARNING_STR", "The inserted text exceeded the maximum length of this text field. The text was truncated.") + +#define SV_APP_CPUTHREADS NC_("SV_APP_CPUTHREADS", "CPU threads: ") +#define SV_APP_OSVERSION NC_("SV_APP_OSVERSION", "OS: ") +#define SV_APP_UIRENDER NC_("SV_APP_UIRENDER", "UI render: ") +#define SV_APP_GL NC_("SV_APP_GL", "GL") +#define SV_APP_SKIA_VULKAN NC_("SV_APP_SKIA_VULKAN", "Skia/Vulkan") +#define SV_APP_SKIA_RASTER NC_("SV_APP_SKIA_RASTER", "Skia/Raster") +#define SV_APP_DEFAULT NC_("SV_APP_DEFAULT", "default") + +#define SV_MSGBOX_INFO NC_("SV_MSGBOX_INFO", "Information") +#define SV_MSGBOX_WARNING NC_("SV_MSGBOX_WARNING", "Warning") +#define SV_MSGBOX_ERROR NC_("SV_MSGBOX_ERROR", "Error") +#define SV_MSGBOX_QUERY NC_("SV_MSGBOX_QUERY", "Confirmation") + +#define STR_TEXTUNDO_DELPARA NC_("STR_TEXTUNDO_DELPARA", "delete line") +#define STR_TEXTUNDO_CONNECTPARAS NC_("STR_TEXTUNDO_CONNECTPARAS", "delete multiple lines") +#define STR_TEXTUNDO_SPLITPARA NC_("STR_TEXTUNDO_SPLITPARA", "insert multiple lines") +#define STR_TEXTUNDO_INSERTCHARS NC_("STR_TEXTUNDO_INSERTCHARS", "insert '$1'") +#define STR_TEXTUNDO_REMOVECHARS NC_("STR_TEXTUNDO_REMOVECHARS", "delete '$1'") + +// descriptions of accessible objects +#define STR_SVT_ACC_DESC_TABLISTBOX NC_("STR_SVT_ACC_DESC_TABLISTBOX", "Row: %1, Column: %2") +#define STR_SVT_ACC_EMPTY_FIELD NC_("STR_SVT_ACC_EMPTY_FIELD", "Empty Field") + +#define STR_SVT_CALENDAR_DAY NC_("STR_SVT_CALENDAR_DAY", "Day") +#define STR_SVT_CALENDAR_WEEK NC_("STR_SVT_CALENDAR_WEEK", "Week") +#define STR_SVT_CALENDAR_TODAY NC_("STR_SVT_CALENDAR_TODAY", "Today") + +#define STR_WIZDLG_ROADMAP_TITLE NC_("STR_WIZDLG_ROADMAP_TITLE", "Steps") +#define STR_WIZDLG_FINISH NC_("STR_WIZDLG_FINISH", "~Finish") +#define STR_WIZDLG_NEXT NC_("STR_WIZDLG_NEXT", "~Next >") +#define STR_WIZDLG_PREVIOUS NC_("STR_WIZDLG_PREVIOUS", "< Bac~k") + +#endif // INCLUDED_VCL_INC_STRINGS_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/strings.hxx b/vcl/inc/strings.hxx new file mode 100644 index 000000000..45e9b2af4 --- /dev/null +++ b/vcl/inc/strings.hxx @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_STRINGS_HXX +#define INCLUDED_VCL_INC_STRINGS_HXX + +#define SV_APP_VCLBACKEND "VCL: " + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx new file mode 100644 index 000000000..46a4a20cf --- /dev/null +++ b/vcl/inc/svdata.hxx @@ -0,0 +1,462 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SVDATA_HXX +#define INCLUDED_VCL_INC_SVDATA_HXX + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vcleventlisteners.hxx" +#include "salwtype.hxx" +#include "displayconnectiondispatch.hxx" + +#include +#include +#include +#include "ControlCacheKey.hxx" +#include "schedulerimpl.hxx" +#include + +struct ImplPostEventData; +struct ImplTimerData; +struct ImplIdleData; +struct ImplConfigData; +class ImplDirectFontSubstitution; +struct ImplHotKey; +struct ImplEventHook; +class Point; +class ImplAccelManager; +class PhysicalFontCollection; +class ImplFontCache; +class HelpTextWindow; +class ImplTBDragMgr; +class ImplIdleMgr; +class FloatingWindow; +class AllSettings; +class NotifyEvent; +class Timer; +class AutoTimer; +class Idle; +class Help; +class Image; +class PopupMenu; +class Application; +class OutputDevice; +class SvFileStream; +class SystemWindow; +class WorkWindow; +class Dialog; +class VirtualDevice; +class Printer; +class SalFrame; +class SalInstance; +class SalSystem; +class ImplPrnQueueList; +class UnoWrapperBase; +class GraphicConverter; +class ImplWheelWindow; +class SalTimer; +class DockingManager; +class VclEventListeners2; +class SalData; +class OpenGLContext; +class UITestLogger; + +#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_PRESENTATION 8 +#define SV_ICON_ID_MASTER_DOCUMENT 10 +#define SV_ICON_ID_TEMPLATE 11 +#define SV_ICON_ID_DATABASE 12 +#define SV_ICON_ID_FORMULA 13 + +namespace com::sun::star::datatransfer::clipboard { class XClipboard; } + +namespace vcl +{ + class DisplayConnectionDispatch; + class SettingsConfigItem; + class DeleteOnDeinitBase; + class Window; +} + +namespace basegfx +{ + class SystemDependentDataManager; +} + +class LocaleConfigurationListener final : public utl::ConfigurationListener +{ +public: + virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override; +}; + +typedef std::vector > SVAppKeyListeners; + +typedef std::pair, ImplPostEventData *> ImplPostEventPair; + +struct ImplSVAppData +{ + ~ImplSVAppData(); + + std::unique_ptr mpSettings; // Application settings + LocaleConfigurationListener* mpCfgListener = nullptr; + VclEventListeners maEventListeners; // listeners for vcl events (eg, extended toolkit) + SVAppKeyListeners maKeyListeners; // listeners for key events only (eg, extended toolkit) + std::vector maPostedEventList; + ImplAccelManager* mpAccelMgr; // Accelerator Manager + std::optional mxAppName; // Application name + std::optional mxAppFileName; // Abs. Application FileName + std::optional mxDisplayName; // Application Display Name + std::optional mxToolkitName; // Toolkit Name + Help* mpHelp = nullptr; // Application help + VclPtr mpActivePopupMenu; // Actives Popup-Menu (in Execute) + VclPtr mpWheelWindow; // WheelWindow + sal_uInt64 mnLastInputTime = 0; // GetLastInputTime() + sal_uInt16 mnDispatchLevel = 0; // DispatchLevel + sal_uInt16 mnModalMode = 0; // ModalMode Count + SystemWindowFlags mnSysWinMode = SystemWindowFlags(0); // Mode, when SystemWindows should be created + bool mbInAppMain = false; // is Application::Main() on stack + bool mbInAppExecute = false; // is Application::Execute() on stack + bool mbAppQuit = false; // is Application::Quit() called + bool mbSettingsInit = false; // true: Settings are initialized + DialogCancelMode meDialogCancel = DialogCancelMode::Off; // true: All Dialog::Execute() calls will be terminated immediately with return false + bool mbRenderToBitmaps = false; // set via svp / headless plugin + + SvFileStream* mpEventTestInput = nullptr; + Idle* mpEventTestingIdle = nullptr; + int mnEventTestLimit = 0; + + DECL_STATIC_LINK(ImplSVAppData, ImplQuitMsg, void*, void); + DECL_STATIC_LINK(ImplSVAppData, ImplPrepareExitMsg, void*, void); + DECL_STATIC_LINK(ImplSVAppData, ImplEndAllDialogsMsg, void*, void); + DECL_STATIC_LINK(ImplSVAppData, ImplEndAllPopupsMsg, void*, void); + DECL_STATIC_LINK(ImplSVAppData, ImplVclEventTestingHdl, void*, void); + DECL_LINK(VclEventTestingHdl, Timer*, void); +}; + +/// Cache multiple scalings for the same bitmap +struct ScaleCacheKey { + SalBitmap *mpBitmap; + Size maDestSize; + ScaleCacheKey(SalBitmap *pBitmap, const Size &aDestSize) + { + mpBitmap = pBitmap; + maDestSize = aDestSize; + } + ScaleCacheKey(const ScaleCacheKey &key) + { + mpBitmap = key.mpBitmap; + maDestSize = key.maDestSize; + } + bool operator==(ScaleCacheKey const& rOther) const + { + return mpBitmap == rOther.mpBitmap && maDestSize == rOther.maDestSize; + } +}; + +namespace std +{ +template <> struct hash +{ + std::size_t operator()(ScaleCacheKey const& k) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, k.mpBitmap); + boost::hash_combine(seed, k.maDestSize.getWidth()); + boost::hash_combine(seed, k.maDestSize.getHeight()); + return seed; + } +}; + +} // end std namespace + +typedef o3tl::lru_map lru_scale_cache; + +struct ImplSVGDIData +{ + ~ImplSVGDIData(); + + VclPtr mpFirstWinGraphics; // First OutputDevice with a Frame Graphics + VclPtr mpLastWinGraphics; // Last OutputDevice with a Frame Graphics + VclPtr mpFirstVirGraphics; // First OutputDevice with a VirtualDevice Graphics + VclPtr mpLastVirGraphics; // Last OutputDevice with a VirtualDevice Graphics + VclPtr mpFirstPrnGraphics; // First OutputDevice with an InfoPrinter Graphics + VclPtr mpLastPrnGraphics; // Last OutputDevice with an InfoPrinter Graphics + VclPtr mpFirstVirDev; // First VirtualDevice + OpenGLContext* mpLastContext = nullptr; // Last OpenGLContext + VclPtr mpFirstPrinter; // First Printer + std::unique_ptr mpPrinterQueueList; // List of all printer queue + std::shared_ptr mxScreenFontList; // Screen-Font-List + std::shared_ptr mxScreenFontCache; // Screen-Font-Cache + lru_scale_cache maScaleCache = lru_scale_cache(10); // Cache for scaled images + ImplDirectFontSubstitution* mpDirectFontSubst = nullptr; // Font-Substitutions defined in Tools->Options->Fonts + GraphicConverter* mpGrfConverter = nullptr; // Converter for graphics + long mnAppFontX = 0; // AppFont X-Numenator for 40/tel Width + long mnAppFontY = 0; // AppFont Y-Numenator for 80/tel Height + bool mbFontSubChanged = false; // true: FontSubstitution was changed between Begin/End + + o3tl::lru_map maThemeImageCache = o3tl::lru_map(10); + o3tl::lru_map maThemeDrawCommandsCache = o3tl::lru_map(50); +}; + +struct ImplSVFrameData +{ + ~ImplSVFrameData(); + VclPtr mpFirstFrame; // First FrameWindow + VclPtr mpActiveApplicationFrame; // the last active application frame, can be used as DefModalDialogParent if no focuswin set + VclPtr mpAppWin; // Application-Window + + std::unique_ptr m_pUITestLogger; +}; + +struct ImplSVWinData +{ + ~ImplSVWinData(); + VclPtr mpFocusWin; // window, that has the focus + VclPtr mpCaptureWin; // window, that has the mouse capture + VclPtr mpLastDeacWin; // Window, that need a deactivate (FloatingWindow-Handling) + VclPtr mpFirstFloat; // First FloatingWindow in PopupMode + std::vector> mpExecuteDialogs; ///< Stack of dialogs that are Execute()'d - the last one is the top most one. + VclPtr mpExtTextInputWin; // Window, which is in ExtTextInput + VclPtr mpTrackWin; // window, that is in tracking mode + AutoTimer* mpTrackTimer = nullptr; // tracking timer + std::vector maMsgBoxImgList; // ImageList for MessageBox + VclPtr mpAutoScrollWin; // window, that is in AutoScrollMode mode + VclPtr mpLastWheelWindow; // window, that last received a mouse wheel event + SalWheelMouseEvent maLastWheelEvent; // the last received mouse wheel event + + StartTrackingFlags mnTrackFlags = StartTrackingFlags::NONE; // tracking flags + StartAutoScrollFlags mnAutoScrollFlags = StartAutoScrollFlags::NONE; // auto scroll flags + bool mbNoDeactivate = false; // true: do not execute Deactivate + bool mbNoSaveFocus = false; // true: menus must not save/restore focus +}; + +typedef std::vector< std::pair< OUString, FieldUnit > > FieldUnitStringList; + +struct ImplSVCtrlData +{ + std::vector maCheckImgList; // ImageList for CheckBoxes + std::vector maRadioImgList; // ImageList for RadioButtons + std::unique_ptr mpDisclosurePlus; + std::unique_ptr mpDisclosureMinus; + ImplTBDragMgr* mpTBDragMgr = nullptr; // DragMgr for ToolBox + sal_uInt16 mnCheckStyle = 0; // CheckBox-Style for ImageList-Update + sal_uInt16 mnRadioStyle = 0; // Radio-Style for ImageList-Update + Color mnLastCheckFColor; // Last FaceColor for CheckImage + Color mnLastCheckWColor; // Last WindowColor for CheckImage + Color mnLastCheckLColor; // Last LightColor for CheckImage + Color mnLastRadioFColor; // Last FaceColor for RadioImage + Color mnLastRadioWColor; // Last WindowColor for RadioImage + Color mnLastRadioLColor; // Last LightColor for RadioImage + FieldUnitStringList maFieldUnitStrings; // list with field units + FieldUnitStringList maCleanUnitStrings; // same list but with some "fluff" like spaces removed +}; + +struct ImplSVHelpData +{ + ~ImplSVHelpData(); + bool mbContextHelp = false; // is ContextHelp enabled + bool mbExtHelp = false; // is ExtendedHelp enabled + bool mbExtHelpMode = false; // is in ExtendedHelp Mode + bool mbOldBalloonMode = false; // BalloonMode, before ExtHelpMode started + bool mbBalloonHelp = false; // is BalloonHelp enabled + bool mbQuickHelp = false; // is QuickHelp enabled + bool mbSetKeyboardHelp = false; // tiphelp was activated by keyboard + bool mbKeyboardHelp = false; // tiphelp was activated by keyboard + bool mbRequestingHelp = false; // In Window::RequestHelp + VclPtr mpHelpWin; // HelpWindow + sal_uInt64 mnLastHelpHideTime = 0; // ticks of last show +}; + +// "NWF" means "Native Widget Framework" and was the term used for the +// idea that StarView/OOo "widgets" should *look* (and feel) like the +// "native widgets" on each platform, even if not at all implemented +// using them. See http://people.redhat.com/dcbw/ooo-nwf.html . + +struct ImplSVNWFData +{ + int mnStatusBarLowerRightOffset = 0; // amount in pixel to avoid in the lower righthand corner + int mnMenuFormatBorderX = 0; // horizontal inner popup menu border + int mnMenuFormatBorderY = 0; // vertical inner popup menu border + ::Color maMenuBarHighlightTextColor = COL_TRANSPARENT; // override highlight text color + // in menubar if not transparent + bool mbMenuBarDockingAreaCommonBG = false; // e.g. WinXP default theme + bool mbDockingAreaSeparateTB = false; // individual toolbar backgrounds + // instead of one for docking area + bool mbDockingAreaAvoidTBFrames = false; ///< don't draw frames around the individual toolbars if mbDockingAreaSeparateTB is false + bool mbFlatMenu = false; // no popup 3D border + bool mbNoFocusRects = false; // on Aqua/Gtk3 use native focus rendering, except for flat buttons + bool mbNoFocusRectsForFlatButtons = false; // on Gtk3 native focusing is also preferred for flat buttons + bool mbCenteredTabs = false; // on Aqua, tabs are centered + bool mbNoActiveTabTextRaise = false; // on Aqua the text for the selected tab + // should not "jump up" a pixel + bool mbProgressNeedsErase = false; // set true for platforms that should draw the + // window background before drawing the native + // progress bar + bool mbCanDrawWidgetAnySize = false; // set to true currently on gtk + + /// entire drop down listbox resembles a button, no textarea/button parts (as currently on Windows) + bool mbDDListBoxNoTextArea = false; + bool mbAutoAccel = false; // whether accelerators are only shown when Alt is held down + bool mbRolloverMenubar = false; // theming engine supports rollover in menubar + // gnome#768128 I cannot see a route under wayland at present to support + // floating toolbars that can be redocked because there's no way to track + // that the toolbar is over a dockable area. + bool mbCanDetermineWindowPosition = true; + + int mnListBoxEntryMargin = 0; +}; + +struct BlendFrameCache +{ + Size m_aLastSize; + sal_uInt8 m_nLastAlpha; + Color m_aLastColorTopLeft; + Color m_aLastColorTopRight; + Color m_aLastColorBottomRight; + Color m_aLastColorBottomLeft; + BitmapEx m_aLastResult; + + BlendFrameCache() + : m_aLastSize(0, 0) + , m_nLastAlpha(0) + , m_aLastColorTopLeft(COL_BLACK) + , m_aLastColorTopRight(COL_BLACK) + , m_aLastColorBottomRight(COL_BLACK) + , m_aLastColorBottomLeft(COL_BLACK) + { + } +}; + +struct ImplSchedulerContext +{ + ImplSchedulerData* mpFirstSchedulerData[PRIO_COUNT] = { nullptr, }; ///< list of all active tasks per priority + ImplSchedulerData* mpLastSchedulerData[PRIO_COUNT] = { nullptr, }; ///< last item of each mpFirstSchedulerData list + ImplSchedulerData* mpSchedulerStack = nullptr; ///< stack of invoked tasks + ImplSchedulerData* mpSchedulerStackTop = nullptr; ///< top most stack entry to detect needed rescheduling during pop + SalTimer* mpSalTimer = nullptr; ///< interface to sal event loop / system timer + sal_uInt64 mnTimerStart = 0; ///< start time of the timer + sal_uInt64 mnTimerPeriod = SAL_MAX_UINT64; ///< current timer period + SchedulerMutex maMutex; ///< lock counting mutex for scheduler locking + bool mbActive = true; ///< is the scheduler active? +}; + +struct ImplSVData +{ + ImplSVData(); + ~ImplSVData(); + SalData* mpSalData = nullptr; + SalInstance* mpDefInst = nullptr; // Default SalInstance + Application* mpApp = nullptr; // pApp + VclPtr mpDefaultWin; // Default-Window + bool mbDeInit = false; // Is VCL deinitializing + std::unique_ptr mpSalSystem; // SalSystem interface + bool mbResLocaleSet = false; // SV-Resource-Manager + std::locale maResLocale; // Resource locale + ImplSchedulerContext maSchedCtx; // Data for class Scheduler + ImplSVAppData maAppData; // Data for class Application + ImplSVGDIData maGDIData; // Data for Output classes + ImplSVFrameData maFrameData; // Data for Frame classes + ImplSVWinData* mpWinData = nullptr; // Data for per-view Windows classes + ImplSVCtrlData maCtrlData; // Data for Control classes + ImplSVHelpData* mpHelpData; // Data for Help classes + ImplSVNWFData maNWFData; + UnoWrapperBase* mpUnoWrapper = nullptr; + VclPtr mpIntroWindow; // the splash screen + std::unique_ptr mpDockingManager; + std::unique_ptr mpBlendFrameCache; + + oslThreadIdentifier mnMainThreadId = 0; + rtl::Reference< vcl::DisplayConnectionDispatch > mxDisplayConnection; + + css::uno::Reference< css::lang::XComponent > mxAccessBridge; + std::unique_ptr mpSettingsConfigItem; + std::vector< vcl::DeleteOnDeinitBase* > maDeinitDeleteList; + std::unordered_map< int, OUString > maPaperNames; + + css::uno::Reference m_xCharClass; + +#if defined _WIN32 + css::uno::Reference m_xSystemClipboard; +#endif + + Link maDeInitHook; + + // LOK & headless backend specific hooks + LibreOfficeKitPollCallback mpPollCallback = nullptr; + LibreOfficeKitWakeCallback mpWakeCallback = nullptr; + void *mpPollClosure = nullptr; +}; + +css::uno::Reference const& ImplGetCharClass(); + +void ImplDeInitSVData(); +VCL_PLUGIN_PUBLIC basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager(); +VCL_PLUGIN_PUBLIC vcl::Window* ImplGetDefaultWindow(); +vcl::Window* ImplGetDefaultContextWindow(); +const std::locale& ImplGetResLocale(); +VCL_PLUGIN_PUBLIC OUString VclResId(const char* pId); +DockingManager* ImplGetDockingManager(); +BlendFrameCache* ImplGetBlendFrameCache(); + +VCL_PLUGIN_PUBLIC ImplSVHelpData& ImplGetSVHelpData(); + +VCL_DLLPUBLIC bool ImplCallPreNotify( NotifyEvent& rEvt ); + +VCL_PLUGIN_PUBLIC ImplSVData* ImplGetSVData(); +VCL_PLUGIN_PUBLIC void ImplHideSplash(); + +#ifdef _WIN32 +bool ImplInitAccessBridge(); +#endif + +const FieldUnitStringList& ImplGetFieldUnits(); +const FieldUnitStringList& ImplGetCleanedFieldUnits(); + +struct ImplSVEvent +{ + void* mpData; + Link maLink; + VclPtr mpInstanceRef; + VclPtr mpWindow; + bool mbCall; +}; + +extern int nImplSysDialog; + +#endif // INCLUDED_VCL_INC_SVDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/svimpbox.hxx b/vcl/inc/svimpbox.hxx new file mode 100644 index 000000000..c5a51143f --- /dev/null +++ b/vcl/inc/svimpbox.hxx @@ -0,0 +1,398 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_SOURCE_INC_SVIMPBOX_HXX +#define INCLUDED_VCL_SOURCE_INC_SVIMPBOX_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class SvLBoxButton; +class SvTreeList; +class SvImpLBox; +class SvTreeListEntry; +namespace comphelper +{ + namespace string + { + class NaturalStringSorter; + } +} + +class ImpLBSelEng final : public FunctionSet +{ + SvImpLBox* pImp; + VclPtr pView; + +public: + ImpLBSelEng( SvImpLBox* pImp, SvTreeListBox* pView ); + virtual ~ImpLBSelEng() override; + void BeginDrag() override; + void CreateAnchor() override; + void DestroyAnchor() override; + void SetCursorAtPoint( const Point& rPoint, + bool bDontSelectAtCursor=false ) override; + bool IsSelectionAtPoint( const Point& rPoint ) override; + void DeselectAtPoint( const Point& rPoint ) override; + void DeselectAll() override; +}; + +// Flags for nFlag +enum class LBoxFlags { + NONE = 0x0000, + InScrolling = 0x0001, + DeselectAll = 0x0002, + StartEditTimer = 0x0004, // MAC only + IgnoreSelect = 0x0008, + InResize = 0x0010, + RemovedEntryInvisible = 0x0020, + RemovedRecalcMostRight = 0x0040, + IgnoreChangedTabs = 0x0080, + InPaint = 0x0100, + EndScrollSetVisSize = 0x0200, + Filling = 0x0400, +}; +namespace o3tl +{ + template<> struct typed_flags : is_typed_flags {}; +} + +#define NODE_BMP_TABDIST_NOTVALID -2000000 +#define FIRST_ENTRY_TAB 1 + +class SvImpLBox +{ +friend class ImpLBSelEng; +friend class SvTreeListBox; +friend class SalInstanceTreeView; +friend class IconView; +private: + SvTreeList* m_pTree; + SvTreeListEntry* m_pAnchor; + SvTreeListEntry* m_pMostRightEntry; + SvLBoxButton* m_pActiveButton; + SvTreeListEntry* m_pActiveEntry; + SvLBoxTab* m_pActiveTab; + + VclPtr m_aHorSBar; + VclPtr m_aScrBarBox; + + ::vcl::AccessibleFactoryAccess + m_aFactoryAccess; + + static Image* s_pDefCollapsed; + static Image* s_pDefExpanded; + static oslInterlockedCount s_nImageRefCount; /// When 0 all static images will be destroyed + + // Node Bitmaps + enum class ImageType + { + NodeExpanded = 0, // node is expanded ( usually a bitmap showing a minus ) + NodeCollapsed, // node is collapsed ( usually a bitmap showing a plus ) + NodeDontKnow, // don't know the node state + EntryDefExpanded, // default for expanded entries + EntryDefCollapsed, // default for collapsed entries + LAST = EntryDefCollapsed + }; + + // all our images + o3tl::enumarray + m_aNodeAndEntryImages; + + ImpLBSelEng m_aFctSet; + + long m_nNodeBmpWidth; + long m_nMostRight; + short m_nHorSBarHeight, m_nVerSBarWidth; + + bool m_bUpdateMode : 1; + bool m_bSubLstOpLR : 1; // open/close sublist with cursor left/right, defaulted with false + bool m_bContextMenuHandling : 1; + bool mbForceMakeVisible; + + Point m_aEditClickPos; + Idle m_aEditIdle; + + std::unique_ptr m_pStringSorter; + + std::vector< short > m_aContextBmpWidthVector; + + DECL_LINK(EditTimerCall, Timer *, void); + + void InvalidateEntriesFrom( long nY ) const; + bool IsLineVisible( long nY ) const; + void KeyLeftRight( long nDiff ); + + void DrawNet(vcl::RenderContext& rRenderContext); + + // ScrollBar-Handler + DECL_LINK( ScrollUpDownHdl, ScrollBar*, void ); + DECL_LINK( ScrollLeftRightHdl, ScrollBar*, void ); + DECL_LINK( EndScrollHdl, ScrollBar*, void ); + + void SetNodeBmpWidth( const Image& ); + void SetNodeBmpTabDistance(); + + // Selection-Engine + SvTreeListEntry* MakePointVisible( const Point& rPoint ); + + void SetAnchorSelection( SvTreeListEntry* pOld, + SvTreeListEntry* pNewCursor ); + void BeginDrag(); + bool ButtonDownCheckCtrl( const MouseEvent& rMEvt, SvTreeListEntry* pEntry ); + bool MouseMoveCheckCtrl( const MouseEvent& rMEvt, SvTreeListEntry const * pEntry ); + bool ButtonUpCheckCtrl( const MouseEvent& rMEvt ); + bool ButtonDownCheckExpand( const MouseEvent&, SvTreeListEntry* ); + + bool EntryReallyHit(SvTreeListEntry* pEntry, const Point& rPos, long nLine); + void InitScrollBarBox(); + SvLBoxTab* NextTab( SvLBoxTab const * ); + + bool SetMostRight( SvTreeListEntry* pEntry ); + void FindMostRight( SvTreeListEntry* pParent ); + void FindMostRight_Impl( SvTreeListEntry* pParent ); + void NotifyTabsChanged(); + + // if element at cursor can be expanded in general + bool IsExpandable() const; + + static void implInitDefaultNodeImages(); + + void UpdateStringSorter(); + + short UpdateContextBmpWidthVector( SvTreeListEntry const * pEntry, short nWidth ); + void UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry ); + void UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry ); + + void ExpandAll(); + void CollapseTo(SvTreeListEntry* pParentToCollapse); + +protected: + VclPtr m_pView; + VclPtr m_aVerSBar; + SvTreeListEntry* m_pCursor; + SvTreeListEntry* m_pStartEntry; + ImplSVEvent* m_nCurUserEvent; + Size m_aOutputSize; + LBoxFlags m_nFlags; + WinBits m_nStyle; + bool mbNoAutoCurEntry; // disable the behavior of automatically selecting a "CurEntry" upon painting the control + SelectionEngine m_aSelEng; + sal_uLong m_nVisibleCount; // Number of lines in control + bool m_bInVScrollHdl : 1; + bool m_bSimpleTravel : 1; // is true if SelectionMode::Single + long m_nNextVerVisSize; + long m_nNodeBmpTabDistance; // typical smaller than 0 + + virtual long GetEntryLine(const SvTreeListEntry* pEntry) const; + virtual void CursorDown(); + virtual void CursorUp(); + virtual void PageDown( sal_uInt16 nDelta ); + virtual void PageUp( sal_uInt16 nDelta ); + // set Thumb to FirstEntryToDraw + virtual void SyncVerThumb(); + virtual void AdjustScrollBars( Size& rSize ); + virtual void InvalidateEntry( long nY ) const; + + tools::Rectangle GetVisibleArea() const; + void SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect = false ); + void BeginScroll(); + void EndScroll(); + void PositionScrollBars( Size& rOSize, sal_uInt16 nMask ); + void FindMostRight(); + void FillView(); + void ShowVerSBar(); + void StopUserEvent(); + + DECL_LINK( MyUserEvent, void*, void); + +public: + SvImpLBox( SvTreeListBox* pView, SvTreeList*, WinBits nWinStyle ); + virtual ~SvImpLBox(); + + void Clear(); + void SetStyle( WinBits i_nWinStyle ); + void SetNoAutoCurEntry( bool b ); + void SetModel( SvTreeList* pModel ) { m_pTree = pModel;} + + void EntryInserted( SvTreeListEntry*); + void RemovingEntry( SvTreeListEntry* pEntry ); + void EntryRemoved(); + void MovingEntry( SvTreeListEntry* pEntry ); + void EntryMoved( SvTreeListEntry* pEntry ); + void TreeInserted( SvTreeListEntry* pEntry ); + + void EntryExpanded( SvTreeListEntry* pEntry ); + void EntryCollapsed( SvTreeListEntry* pEntry ); + void CollapsingEntry( SvTreeListEntry* pEntry ); + void EntrySelected( SvTreeListEntry* pEntry, bool bSelect ); + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void MouseButtonDown( const MouseEvent& ); + void MouseButtonUp( const MouseEvent& ); + void MouseMove( const MouseEvent&); + virtual bool KeyInput( const KeyEvent& ); + void Resize(); + void GetFocus(); + void LoseFocus(); + virtual void UpdateAll( bool bInvalidateCompleteView ); + void SetEntryHeight(); + void InvalidateEntry( SvTreeListEntry* ); + void RecalcFocusRect(); + + void SelectEntry( SvTreeListEntry* pEntry, bool bSelect ); + void SetDragDropMode( DragDropMode eDDMode ); + void SetSelectionMode( SelectionMode eSelMode ); + + virtual bool IsEntryInView( SvTreeListEntry* pEntry ) const; + virtual SvTreeListEntry* GetEntry( const Point& rPos ) const; + // returns last entry, if Pos below last entry + virtual SvTreeListEntry* GetClickedEntry( const Point& ) const; + SvTreeListEntry* GetCurEntry() const { return m_pCursor; } + void SetCurEntry( SvTreeListEntry* ); + virtual Point GetEntryPosition(const SvTreeListEntry*) const; + void MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop = false ); + void ScrollToAbsPos( long nPos ); + + void PaintDDCursor(SvTreeListEntry* pEntry, bool bShow); + + // Images + inline Image& implGetImageLocation( const ImageType _eType ); + + inline void SetExpandedNodeBmp( const Image& _rImg ); + inline void SetCollapsedNodeBmp( const Image& _rImg ); + + inline const Image& GetExpandedNodeBmp( ); + inline const Image& GetCollapsedNodeBmp( ); + inline const Image& GetDontKnowNodeBmp( ); + + inline void SetDefaultEntryExpBmp( const Image& _rImg ); + inline void SetDefaultEntryColBmp( const Image& _rImg ); + inline const Image& GetDefaultEntryExpBmp( ); + inline const Image& GetDefaultEntryColBmp( ); + + static const Image& GetDefaultExpandedNodeImage( ); + static const Image& GetDefaultCollapsedNodeImage( ); + + const Size& GetOutputSize() const { return m_aOutputSize;} + virtual void KeyUp( bool bPageUp ); + virtual void KeyDown( bool bPageDown ); + void Command( const CommandEvent& rCEvt ); + + void Invalidate(); + void DestroyAnchor() { m_pAnchor=nullptr; m_aSelEng.Reset(); } + void SelAllDestrAnch( bool bSelect, bool bDestroyAnchor = true, bool bSingleSelToo = false ); + void ShowCursor( bool bShow ); + + bool RequestHelp( const HelpEvent& rHEvt ); + void EndSelection(); + bool IsNodeButton( const Point& rPosPixel, SvTreeListEntry* pEntry ) const; + void SetUpdateMode( bool bMode ); + bool GetUpdateMode() const { return m_bUpdateMode; } + tools::Rectangle GetClipRegionRect() const; + bool HasHorScrollBar() const { return m_aHorSBar->IsVisible(); } + void ShowFocusRect( const SvTreeListEntry* pEntry ); + void CallEventListeners( VclEventId nEvent, void* pData = nullptr ); + + bool IsSelectable( const SvTreeListEntry* pEntry ); + void SetForceMakeVisible(bool bEnable) { mbForceMakeVisible = bEnable; } +}; + +inline Image& SvImpLBox::implGetImageLocation( const ImageType _eType ) +{ + return m_aNodeAndEntryImages[_eType]; +} + +inline void SvImpLBox::SetExpandedNodeBmp( const Image& rImg ) +{ + implGetImageLocation( ImageType::NodeExpanded ) = rImg; + SetNodeBmpWidth( rImg ); +} + +inline void SvImpLBox::SetCollapsedNodeBmp( const Image& rImg ) +{ + implGetImageLocation( ImageType::NodeCollapsed ) = rImg; + SetNodeBmpWidth( rImg ); +} + +inline const Image& SvImpLBox::GetDontKnowNodeBmp( ) +{ + return implGetImageLocation( ImageType::NodeDontKnow ); +} + +inline const Image& SvImpLBox::GetExpandedNodeBmp( ) +{ + return implGetImageLocation( ImageType::NodeExpanded ); +} + +inline const Image& SvImpLBox::GetCollapsedNodeBmp( ) +{ + return implGetImageLocation( ImageType::NodeCollapsed ); +} + +inline void SvImpLBox::SetDefaultEntryExpBmp( const Image& _rImg ) +{ + implGetImageLocation( ImageType::EntryDefExpanded ) = _rImg; +} + +inline void SvImpLBox::SetDefaultEntryColBmp( const Image& _rImg ) +{ + implGetImageLocation( ImageType::EntryDefCollapsed ) = _rImg; +} + +inline const Image& SvImpLBox::GetDefaultEntryExpBmp( ) +{ + return implGetImageLocation( ImageType::EntryDefExpanded ); +} + +inline const Image& SvImpLBox::GetDefaultEntryColBmp( ) +{ + return implGetImageLocation( ImageType::EntryDefCollapsed ); +} + +inline Point SvImpLBox::GetEntryPosition(const SvTreeListEntry* pEntry) const +{ + return Point(0, GetEntryLine(pEntry)); +} + +inline bool SvImpLBox::IsLineVisible( long nY ) const +{ + bool bRet = true; + if ( nY < 0 || nY >= m_aOutputSize.Height() ) + bRet = false; + return bRet; +} + +inline void SvImpLBox::TreeInserted( SvTreeListEntry* pInsTree ) +{ + EntryInserted( pInsTree ); +} + +#endif // INCLUDED_VCL_SOURCE_INC_SVIMPBOX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/svmconverter.hxx b/vcl/inc/svmconverter.hxx new file mode 100644 index 000000000..459f327d4 --- /dev/null +++ b/vcl/inc/svmconverter.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SVMCONVERTER_HXX +#define INCLUDED_VCL_INC_SVMCONVERTER_HXX + +#include +#include + +#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_BITMAP_ACTION 17 +#define GDI_BITMAPSCALE_ACTION 18 +#define GDI_PEN_ACTION 19 +#define GDI_FONT_ACTION 20 +#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_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 + +#define GDI_LINECAP_ACTION 1036 + +/** + * Converts old SVGDI aka SVM1 format data to current VCLMTF aka SVM2 format metafile data. + */ +class SVMConverter +{ +private: + static void ImplConvertFromSVM1( SvStream& rIStm, GDIMetaFile& rMtf ); + +public: + SVMConverter( SvStream& rIStm, GDIMetaFile& rMtf ); + +private: + SVMConverter( const SVMConverter& ) = delete; + SVMConverter& operator=( const SVMConverter& ) = delete; +}; + +#endif // INCLUDED_VCL_INC_SVMCONVERTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/svsys.h b/vcl/inc/svsys.h new file mode 100644 index 000000000..d86985669 --- /dev/null +++ b/vcl/inc/svsys.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SVSYS_H +#define INCLUDED_VCL_INC_SVSYS_H + +#include + +#ifdef _WIN32 +#include "win/svsys.h" +#elif defined MACOSX +#include "osx/svsys.h" +#elif defined IOS +#include "ios/svsys.h" +#elif defined ANDROID +#include "android/svsys.h" +#elif defined HAIKU +#elif !HAVE_FEATURE_UI +#else +#include "unx/svsys.h" +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/test/outputdevice.hxx b/vcl/inc/test/outputdevice.hxx new file mode 100644 index 000000000..b8ad0b67f --- /dev/null +++ b/vcl/inc/test/outputdevice.hxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_OUTDEVTESTS_HXX +#define INCLUDED_VCL_OUTDEVTESTS_HXX + +#include + +namespace vcl { +namespace test { + +/** Rendering test result. + * + * Test either "Passed", "Failed" or "PassedWithQuirks" which means + * the test passed but at least one rendering quirk was detected. + */ +enum class TestResult +{ + Failed, + PassedWithQuirks, + Passed +}; + +/** Common subclass for output device rendering tests. + */ +class VCL_DLLPUBLIC OutputDeviceTestCommon +{ +protected: + + ScopedVclPtr mpVirtualDevice; + tools::Rectangle maVDRectangle; + + static const Color constBackgroundColor; + static const Color constLineColor; + static const Color constFillColor; + +public: + OutputDeviceTestCommon(); + + OUString getRenderBackendName() const; + + void initialSetup(long nWidth, long nHeight, Color aColor, bool bEnableAA = false, bool bAlphaVirtualDevice = false); + + static TestResult checkRectangle(Bitmap& rBitmap); + static TestResult checkRectangleAA(Bitmap& rBitmap); + static TestResult checkFilledRectangle(Bitmap& rBitmap, bool useLineColor); + static TestResult checkLines(Bitmap& rBitmap); + static TestResult checkAALines(Bitmap& rBitmap); + static TestResult checkDiamond(Bitmap& rBitmap); + + static TestResult checkInvertRectangle(Bitmap& rBitmap); + static TestResult checkInvertN50Rectangle(Bitmap& aBitmap); + static TestResult checkInvertTrackFrameRectangle(Bitmap& aBitmap); + + static TestResult checkRectangles(Bitmap& rBitmap, std::vector& aExpectedColors); + static TestResult checkRectangle(Bitmap& rBitmap, int aLayerNumber, Color aExpectedColor); + + static TestResult checkFilled(Bitmap& rBitmap, tools::Rectangle aRectangle, Color aExpectedColor); + static TestResult checkChecker(Bitmap& rBitmap, sal_Int32 nStartX, sal_Int32 nEndX, + sal_Int32 nStartY, sal_Int32 nEndY, std::vector const & rExpected); + + static void createDiamondPoints(tools::Rectangle rRect, int nOffset, + Point& rPoint1, Point& rPoint2, + Point& rPoint3, Point& rPoint4); + + static void createHorizontalVerticalDiagonalLinePoints(tools::Rectangle rRect, + Point& rHorizontalLinePoint1, Point& rHorizontalLinePoint2, + Point& rVerticalLinePoint1, Point& rVerticalLinePoint2, + Point& rDiagonalLinePoint1, Point& rDiagonalLinePoint2); + // tools + static tools::Rectangle alignToCenter(tools::Rectangle aRect1, tools::Rectangle aRect2); + + static TestResult checkBezier(Bitmap& rBitmap); +}; + +class VCL_DLLPUBLIC OutputDeviceTestBitmap : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestBitmap() = default; + + Bitmap setupDrawTransformedBitmap(); + Bitmap setupDrawBitmap(); + Bitmap setupDrawBitmapExWithAlpha(); + Bitmap setupDrawMask(); + BitmapEx setupDrawBlend(); + + static TestResult checkTransformedBitmap(Bitmap& rBitmap); + static TestResult checkBitmapExWithAlpha(Bitmap& rBitmap); + static TestResult checkMask(Bitmap& rBitmap); + static TestResult checkBlend(BitmapEx& rBitmap); +}; + +class VCL_DLLPUBLIC OutputDeviceTestAnotherOutDev : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestAnotherOutDev() = default; + + Bitmap setupDrawOutDev(); + Bitmap setupXOR(); + + static TestResult checkDrawOutDev(Bitmap& rBitmap); + static TestResult checkXOR(Bitmap& rBitmap); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPixel : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPixel() = default; + + Bitmap setupRectangle(bool bEnableAA); +}; + +class VCL_DLLPUBLIC OutputDeviceTestLine : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestLine() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupDiamond(); + Bitmap setupLines(); + Bitmap setupAALines(); + + Bitmap setupDashedLine(); + static TestResult checkDashedLine(Bitmap& rBitmap); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPolyLine : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPolyLine() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupDiamond(); + Bitmap setupLines(); + Bitmap setupAALines(); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPolyLineB2D : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPolyLineB2D() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupDiamond(); + Bitmap setupBezier(); + Bitmap setupAABezier(); +}; + +class VCL_DLLPUBLIC OutputDeviceTestRect : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestRect() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupFilledRectangle(bool useLineColor); + Bitmap setupInvert_NONE(); + Bitmap setupInvert_N50(); + Bitmap setupInvert_TrackFrame(); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPolygon : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPolygon() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupFilledRectangle(bool useLineColor); + Bitmap setupDiamond(); + Bitmap setupLines(); + Bitmap setupAALines(); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPolyPolygon : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPolyPolygon() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupFilledRectangle(bool useLineColor); +}; + +class VCL_DLLPUBLIC OutputDeviceTestPolyPolygonB2D : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestPolyPolygonB2D() = default; + + Bitmap setupRectangle(bool bEnableAA); + Bitmap setupFilledRectangle(bool useLineColor); +}; + +class VCL_DLLPUBLIC OutputDeviceTestGradient : public OutputDeviceTestCommon +{ +public: + OutputDeviceTestGradient() = default; + + Bitmap setupLinearGradient(); + Bitmap setupRadialGradient(); +}; + +class VCL_DLLPUBLIC OutputDeviceTestClip : public OutputDeviceTestCommon +{ +public: + Bitmap setupClipRectangle(); + Bitmap setupClipPolygon(); + Bitmap setupClipPolyPolygon(); + Bitmap setupClipB2DPolyPolygon(); + + static TestResult checkClip(Bitmap& rBitmap); +}; + + +}} // end namespace vcl::test + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/textlayout.hxx b/vcl/inc/textlayout.hxx new file mode 100644 index 000000000..e26cc6219 --- /dev/null +++ b/vcl/inc/textlayout.hxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_TEXTLAYOUT_HXX +#define INCLUDED_VCL_INC_TEXTLAYOUT_HXX + +#include + +class Control; + +namespace vcl +{ + class SAL_NO_VTABLE ITextLayout + { + public: + virtual long GetTextWidth( const OUString& _rText, sal_Int32 _nStartIndex, sal_Int32 _nLength ) const = 0; + virtual void DrawText( const Point& _rStartPoint, const OUString& _rText, sal_Int32 _nStartIndex, sal_Int32 _nLength, + MetricVector* _pVector, OUString* _pDisplayText ) = 0; + virtual void GetCaretPositions( const OUString& _rText, long* _pCaretXArray, sal_Int32 _nStartIndex, sal_Int32 _nLength ) const = 0; + virtual sal_Int32 GetTextBreak( const OUString& _rText, long _nMaxTextWidth, sal_Int32 _nStartIndex, sal_Int32 _nLength ) const = 0; + virtual bool DecomposeTextRectAction() const = 0; + + protected: + ~ITextLayout() COVERITY_NOEXCEPT_FALSE {} + }; + + /** 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 final : public ITextLayout + { + public: + DefaultTextLayout( OutputDevice& _rTargetDevice ) + : m_rTargetDevice( _rTargetDevice ) + { + } + virtual ~DefaultTextLayout(); + + // ITextLayout overridables + virtual long GetTextWidth( const OUString& _rText, + sal_Int32 _nStartIndex, + sal_Int32 _nLength ) const override; + + virtual void DrawText( const Point& _rStartPoint, + const OUString& _rText, + sal_Int32 _nStartIndex, + sal_Int32 _nLength, + MetricVector* _pVector, + OUString* _pDisplayText ) override; + + virtual void GetCaretPositions( const OUString& _rText, + long* _pCaretXArray, + sal_Int32 _nStartIndex, + sal_Int32 _nLength ) const override; + + virtual sal_Int32 GetTextBreak( const OUString& _rText, + long _nMaxTextWidth, + sal_Int32 _nStartIndex, + sal_Int32 _nLength ) const override; + + virtual bool DecomposeTextRectAction() const override; + + private: + OutputDevice& m_rTargetDevice; + }; + + 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 final + { + public: + ControlTextRenderer( const Control& _rControl, OutputDevice& _rTargetDevice, OutputDevice& _rReferenceDevice ); + ~ControlTextRenderer(); + + tools::Rectangle DrawText( const tools::Rectangle& _rRect, + const OUString& _rText, DrawTextFlags _nStyle, + MetricVector* _pVector, OUString* _pDisplayText, const Size* i_pDeviceSize ); + + tools::Rectangle GetTextRect( const tools::Rectangle& _rRect, + const OUString& _rText, DrawTextFlags _nStyle, Size* o_pDeviceSize ); + + private: + ControlTextRenderer( const ControlTextRenderer& ) = delete; + ControlTextRenderer& operator=( const ControlTextRenderer& ) = delete; + + private: + ::std::unique_ptr< ReferenceDeviceTextLayout > m_pImpl; + }; + +} // namespace vcl + +#endif // INCLUDED_VCL_INC_TEXTLAYOUT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/textlineinfo.hxx b/vcl/inc/textlineinfo.hxx new file mode 100644 index 000000000..03b19ede9 --- /dev/null +++ b/vcl/inc/textlineinfo.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_TEXTLINEINFO_HXX +#define INCLUDED_VCL_INC_TEXTLINEINFO_HXX + +#include +#include + +class ImplTextLineInfo +{ +private: + long mnWidth; + sal_Int32 mnIndex; + sal_Int32 mnLen; + +public: + ImplTextLineInfo( long nWidth, sal_Int32 nIndex, sal_Int32 nLen ) + { + mnWidth = nWidth; + mnIndex = nIndex; + mnLen = nLen; + } + + long GetWidth() const { return mnWidth; } + sal_Int32 GetIndex() const { return mnIndex; } + sal_Int32 GetLen() const { return mnLen; } +}; + +#define MULTITEXTLINEINFO_RESIZE 16 + +class ImplMultiTextLineInfo +{ +public: + ImplMultiTextLineInfo(); + ~ImplMultiTextLineInfo(); + + void AddLine( ImplTextLineInfo* pLine ); + void Clear(); + + ImplTextLineInfo* GetLine( sal_Int32 nLine ) const + { return mvLines[nLine].get(); } + sal_Int32 Count() const { return mvLines.size(); } + +private: + ImplMultiTextLineInfo( const ImplMultiTextLineInfo& ) = delete; + ImplMultiTextLineInfo& operator=( const ImplMultiTextLineInfo& ) = delete; + + std::vector> mvLines; + +}; + +#endif // INCLUDED_VCL_INC_TEXTLINEINFO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/textrender.hxx b/vcl/inc/textrender.hxx new file mode 100644 index 000000000..1aec8fba2 --- /dev/null +++ b/vcl/inc/textrender.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CAIROFONTIMPL_HXX +#define INCLUDED_VCL_INC_UNX_CAIROFONTIMPL_HXX + +#include "salgdi.hxx" + +#include + +class ImplLayoutArgs; +class ImplFontMetricData; +class PhysicalFontCollection; +class PhysicalFontFace; + +class TextRenderImpl +{ +public: + // can't call ReleaseFonts here, as the destructor just calls this classes SetFont (pure virtual)! + virtual ~TextRenderImpl() {} + + virtual void SetTextColor( Color nColor ) = 0; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) = 0; + void ReleaseFonts() { SetFont(nullptr, 0); } + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) = 0; + virtual FontCharMapRef GetFontCharMap() const = 0; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const = 0; + virtual void GetDevFontList( PhysicalFontCollection* ) = 0; + virtual void ClearDevFontCache() = 0; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) = 0; + virtual bool CreateFontSubset( + const OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo) = 0; + + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) = 0; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) = 0; + virtual void GetGlyphWidths( + const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) = 0; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) = 0; + virtual void DrawTextLayout(const GenericSalLayout&, const SalGraphics&) = 0; +#if ENABLE_CAIRO_CANVAS + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const = 0; +#endif // ENABLE_CAIRO_CANVAS +}; + +#endif + +/* vim:set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/toolbox.h b/vcl/inc/toolbox.h new file mode 100644 index 000000000..bf4c51c5d --- /dev/null +++ b/vcl/inc/toolbox.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_TOOLBOX_H +#define INCLUDED_VCL_INC_TOOLBOX_H + +#include +#include + +#include + +#define TB_DROPDOWNARROWWIDTH 11 + +#define TB_MENUBUTTON_SIZE 12 +#define TB_MENUBUTTON_OFFSET 2 + +namespace vcl { class Window; } + +struct ImplToolItem +{ + VclPtr mpWindow; //don't dispose mpWindow - we get copied around + bool mbNonInteractiveWindow; + void* mpUserData; + Image maImage; + long mnImageAngle; + bool mbMirrorMode; + OUString maText; + OUString maQuickHelpText; + OUString maHelpText; + OUString maCommandStr; + OString maHelpId; + tools::Rectangle maRect; + tools::Rectangle maCalcRect; + /// Widget layout may request size; set it as the minimal size (like, the item will always have at least this size). + Size maMinimalItemSize; + /// The overall horizontal item size, including one or more of [image size + textlength + dropdown arrow] + Size maItemSize; + long mnSepSize; + long mnDropDownArrowWidth; + /// Size of the content (bitmap or text, without dropdown) that we have in the item. + Size maContentSize; + ToolBoxItemType meType; + ToolBoxItemBits mnBits; + TriState meState; + sal_uInt16 mnId; + bool mbEnabled:1, + mbVisible:1, + mbEmptyBtn:1, + mbShowWindow:1, + mbBreak:1, + mbVisibleText:1, // indicates if text will definitely be drawn, influences dropdown pos + mbExpand:1; + + ImplToolItem(); + ImplToolItem( sal_uInt16 nItemId, const Image& rImage, + ToolBoxItemBits nItemBits ); + ImplToolItem( sal_uInt16 nItemId, const OUString& rTxt, + ToolBoxItemBits nItemBits ); + ImplToolItem( sal_uInt16 nItemId, const Image& rImage, + const OUString& rTxt, + ToolBoxItemBits nItemBits ); + + // returns the size of an 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 + tools::Rectangle GetDropDownRect( bool bHorz ) const; + + // returns sal_True if the toolbar item is currently clipped, which can happen for docked toolbars + bool IsClipped() const; + + // returns sal_True if the toolbar item is currently hidden i.e. they are unchecked in the toolbar Customize menu + bool IsItemHidden() const; + +private: + void init(sal_uInt16 nItemId, ToolBoxItemBits nItemBits, bool bEmptyBtn); +}; + +namespace vcl +{ + +struct ToolBoxLayoutData : public ControlLayoutData +{ + std::vector< sal_uInt16 > m_aLineItemIds; +}; + +} /* namespace vcl */ + +struct ImplToolBoxPrivateData +{ + std::unique_ptr m_pLayoutData; + ToolBox::ImplToolItems m_aItems; + + ImplToolBoxPrivateData(); + ~ImplToolBoxPrivateData(); + + void ImplClearLayoutData() { m_pLayoutData.reset(); } + + // 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 + VclPtr mpMenu; + ToolBoxMenuType maMenuType; + + // 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; + + 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 + mbMenubuttonWasLastSelected:1, // menu button was highlighted when focus was lost + 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 // INCLUDED_VCL_INC_TOOLBOX_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/treeglue.hxx b/vcl/inc/treeglue.hxx new file mode 100644 index 000000000..11c61944f --- /dev/null +++ b/vcl/inc/treeglue.hxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include "svimpbox.hxx" + +//the default NotifyStartDrag is weird to me, and defaults to enabling all +//possibilities when drag starts, while restricting it to some subset of +//the configured drag drop mode would make more sense to me, but I'm not +//going to change the baseclass + +class LclHeaderTabListBox final : public SvHeaderTabListBox +{ +private: + Link m_aEditingEntryHdl; + Link, bool> m_aEditedEntryHdl; + +public: + LclHeaderTabListBox(vcl::Window* pParent, WinBits nWinStyle) + : SvHeaderTabListBox(pParent, nWinStyle) + { + } + + void SetEditingEntryHdl(const Link& rLink) + { + m_aEditingEntryHdl = rLink; + } + + void SetEditedEntryHdl(const Link, bool>& rLink) + { + m_aEditedEntryHdl = rLink; + } + + virtual DragDropMode NotifyStartDrag(TransferDataContainer&, SvTreeListEntry*) override + { + return GetDragDropMode(); + } + + virtual bool EditingEntry(SvTreeListEntry* pEntry, Selection&) override + { + return m_aEditingEntryHdl.Call(pEntry); + } + + virtual bool EditedEntry(SvTreeListEntry* pEntry, const OUString& rNewText) override + { + return m_aEditedEntryHdl.Call(std::pair(pEntry, rNewText)); + } +}; + +class LclTabListBox final : public SvTabListBox +{ + Link m_aModelChangedHdl; + Link m_aStartDragHdl; + Link m_aEndDragHdl; + Link m_aEditingEntryHdl; + Link, bool> m_aEditedEntryHdl; + +public: + LclTabListBox(vcl::Window* pParent, WinBits nWinStyle) + : SvTabListBox(pParent, nWinStyle) + { + } + + void SetModelChangedHdl(const Link& rLink) { m_aModelChangedHdl = rLink; } + void SetStartDragHdl(const Link& rLink) { m_aStartDragHdl = rLink; } + void SetEndDragHdl(const Link& rLink) { m_aEndDragHdl = rLink; } + void SetEditingEntryHdl(const Link& rLink) + { + m_aEditingEntryHdl = rLink; + } + void SetEditedEntryHdl(const Link, bool>& rLink) + { + m_aEditedEntryHdl = rLink; + } + + virtual DragDropMode NotifyStartDrag(TransferDataContainer&, SvTreeListEntry*) override + { + return GetDragDropMode(); + } + + virtual void StartDrag(sal_Int8 nAction, const Point& rPosPixel) override + { + if (m_aStartDragHdl.Call(this)) + return; + SvTabListBox::StartDrag(nAction, rPosPixel); + } + + virtual void DragFinished(sal_Int8 nDropAction) override + { + SvTabListBox::DragFinished(nDropAction); + m_aEndDragHdl.Call(this); + } + + virtual void ModelHasCleared() override + { + SvTabListBox::ModelHasCleared(); + m_aModelChangedHdl.Call(this); + } + + virtual void ModelHasInserted(SvTreeListEntry* pEntry) override + { + SvTabListBox::ModelHasInserted(pEntry); + m_aModelChangedHdl.Call(this); + } + + virtual void ModelHasInsertedTree(SvTreeListEntry* pEntry) override + { + SvTabListBox::ModelHasInsertedTree(pEntry); + m_aModelChangedHdl.Call(this); + } + + virtual void ModelHasMoved(SvTreeListEntry* pSource) override + { + SvTabListBox::ModelHasMoved(pSource); + m_aModelChangedHdl.Call(this); + } + + virtual void ModelHasRemoved(SvTreeListEntry* pEntry) override + { + SvTabListBox::ModelHasRemoved(pEntry); + m_aModelChangedHdl.Call(this); + } + + SvTreeListEntry* GetTargetAtPoint(const Point& rPos, bool bHighLightTarget) + { + SvTreeListEntry* pOldTargetEntry = pTargetEntry; + pTargetEntry = pImpl->GetEntry(rPos); + if (pOldTargetEntry != pTargetEntry) + ImplShowTargetEmphasis(pOldTargetEntry, false); + + // scroll + if (rPos.Y() < 12) + { + ImplShowTargetEmphasis(pTargetEntry, false); + ScrollOutputArea(+1); + } + else + { + Size aSize(pImpl->GetOutputSize()); + if (rPos.Y() > aSize.Height() - 12) + { + ImplShowTargetEmphasis(pTargetEntry, false); + ScrollOutputArea(-1); + } + } + + if (pTargetEntry && bHighLightTarget) + ImplShowTargetEmphasis(pTargetEntry, true); + return pTargetEntry; + } + + virtual SvTreeListEntry* GetDropTarget(const Point& rPos) override + { + return GetTargetAtPoint(rPos, true); + } + + virtual bool EditingEntry(SvTreeListEntry* pEntry, Selection&) override + { + return m_aEditingEntryHdl.Call(pEntry); + } + + virtual bool EditedEntry(SvTreeListEntry* pEntry, const OUString& rNewText) override + { + return m_aEditedEntryHdl.Call(std::pair(pEntry, rNewText)); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/uiobject-internal.hxx b/vcl/inc/uiobject-internal.hxx new file mode 100644 index 000000000..accecb2e8 --- /dev/null +++ b/vcl/inc/uiobject-internal.hxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include "wizdlg.hxx" + +class RoadmapWizard; + +class RoadmapWizardUIObject final : public WindowUIObject +{ + VclPtr mxRoadmapWizard; + +public: + RoadmapWizardUIObject(const VclPtr& xRoadmapWizard); + virtual ~RoadmapWizardUIObject() override; + + virtual StringMap get_state() override; + + virtual void execute(const OUString& rAction, const StringMap& rParameters) override; + + static std::unique_ptr create(vcl::Window* pWindow); + +private: + virtual OUString get_name() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/units.hrc b/vcl/inc/units.hrc new file mode 100644 index 000000000..74c449675 --- /dev/null +++ b/vcl/inc/units.hrc @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNITS_HRC +#define INCLUDED_VCL_INC_UNITS_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +std::pair SV_FUNIT_STRINGS[] = +{ + // To translators: This is the first entry of a sequence of measurement unit names + { NC_("SV_FUNIT_STRINGS", "mm"), FieldUnit::MM }, + { NC_("SV_FUNIT_STRINGS", "cm"), FieldUnit::CM }, + { NC_("SV_FUNIT_STRINGS", "m"), FieldUnit::M }, + { NC_("SV_FUNIT_STRINGS", "km"), FieldUnit::KM }, + { NC_("SV_FUNIT_STRINGS", "twips"), FieldUnit::TWIP }, + { NC_("SV_FUNIT_STRINGS", "twip"), FieldUnit::TWIP }, + { NC_("SV_FUNIT_STRINGS", "pt"), FieldUnit::POINT }, + { NC_("SV_FUNIT_STRINGS", "pc"), FieldUnit::PICA }, + /* To translators: double prime symbol for inch */ + { NC_("SV_FUNIT_STRINGS", "″"), FieldUnit::INCH }, + { NC_("SV_FUNIT_STRINGS", "\""), FieldUnit::INCH }, + { NC_("SV_FUNIT_STRINGS", "in"), FieldUnit::INCH }, + { NC_("SV_FUNIT_STRINGS", "inch"), FieldUnit::INCH }, + /* To translators: prime symbol for foot */ + { NC_("SV_FUNIT_STRINGS", "′"), FieldUnit::FOOT }, + { NC_("SV_FUNIT_STRINGS", "'"), FieldUnit::FOOT }, + { NC_("SV_FUNIT_STRINGS", "ft"), FieldUnit::FOOT }, + { NC_("SV_FUNIT_STRINGS", "foot"), FieldUnit::FOOT }, + { NC_("SV_FUNIT_STRINGS", "feet"), FieldUnit::FOOT }, + { NC_("SV_FUNIT_STRINGS", "miles"), FieldUnit::MILE }, + { NC_("SV_FUNIT_STRINGS", "mile"), FieldUnit::MILE }, + { NC_("SV_FUNIT_STRINGS", "ch"), FieldUnit::CHAR }, + { NC_("SV_FUNIT_STRINGS", "line"), FieldUnit::LINE }, + { NC_("SV_FUNIT_STRINGS", "pixels"), FieldUnit::PIXEL }, + { NC_("SV_FUNIT_STRINGS", "pixel"), FieldUnit::PIXEL }, + /* To translators: degree */ + { NC_("SV_FUNIT_STRINGS", "°"), FieldUnit::DEGREE }, + { NC_("SV_FUNIT_STRINGS", "sec"), FieldUnit::SECOND }, + // To translators: This is the last entry of the sequence of measurement unit names + { NC_("SV_FUNIT_STRINGS", "ms"), FieldUnit::MILLISECOND } +}; + +#endif // INCLUDED_VCL_INC_UNITS_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/XIM.h b/vcl/inc/unx/XIM.h new file mode 100644 index 000000000..d2fcd9c0e --- /dev/null +++ b/vcl/inc/unx/XIM.h @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_INC_UNX_XIM_H +#define INCLUDED_VCL_INC_UNX_XIM_H + +#include + +#ifndef XIMCallback1 +typedef int (*XIMProc1)(XIC, XPointer, XPointer); +typedef struct { + XPointer client_data; + XIMProc1 callback; +} XIMCallback1; +#endif + +typedef struct { + int start_position; + int end_position; + XPointer data; +} XIMAnnotation; + +/* + XIMUText: XIMText extension for UTF16 + */ +typedef struct { + 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 { + int choice_per_window; /* Number of choices can be display + * in the region + */ + int nrows; + int ncolumns; + XIMDrawUpDirection draw_up_direction; +} XIMLookupStartCallbackStruct; + +typedef struct { + XIMUnicodeText *label; + XIMUnicodeText *value; +} XIMUnicodeChoiceObject; + +typedef struct { + 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 { + XIMUnicodeCharacterSubsetID index; + XIMUnicodeCharacterSubsetID subset_id; + char *name; + Bool is_active; +} XIMUnicodeCharacterSubset; + +typedef struct { + unsigned short count_subsets; + XIMUnicodeCharacterSubset *supported_subsets; +} XIMUnicodeCharacterSubsets; + +typedef struct { + XIMUnicodeCharacterSubset *from; + XIMUnicodeCharacterSubset *to; +} XIMSwitchIMNotifyCallbackStruct; + +/* XIC attributes for multilingual IM extension */ + +#define XNUnicodeCharacterSubset "UnicodeChararcterSubset" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/cairotextrender.hxx b/vcl/inc/unx/cairotextrender.hxx new file mode 100644 index 000000000..3879bf5d9 --- /dev/null +++ b/vcl/inc/unx/cairotextrender.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_INC_UNX_CAIROTEXTRENDER_HXX + +#include + +typedef struct _cairo cairo_t; + +class VCL_DLLPUBLIC CairoTextRender : public FreeTypeTextRenderImpl +{ +protected: + virtual cairo_t* getCairoContext() = 0; + virtual void getSurfaceOffset(double& nDX, double& nDY) = 0; + virtual void releaseCairoContext(cairo_t* cr) = 0; + + virtual void clipRegion(cairo_t* cr) = 0; + +public: + virtual void DrawTextLayout(const GenericSalLayout&, const SalGraphics&) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/cpdmgr.hxx b/vcl/inc/unx/cpdmgr.hxx new file mode 100644 index 000000000..6449355a1 --- /dev/null +++ b/vcl/inc/unx/cpdmgr.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CPDMGR_HXX +#define INCLUDED_VCL_INC_UNX_CPDMGR_HXX + +#include +#include + +#if ENABLE_DBUS && ENABLE_GIO +#include +#else +typedef struct _GDBusProxy GDBusProxy; +typedef struct _GDBusConnection GDBusConnection; +#endif + +#include +#include "cupsmgr.hxx" + +#define BACKEND_DIR "/usr/share/print-backends" +#define FRONTEND_INTERFACE "/usr/share/dbus-1/interfaces/org.openprinting.Frontend.xml" +#define BACKEND_INTERFACE "/usr/share/dbus-1/interfaces/org.openprinting.Backend.xml" + +namespace psp +{ + +class PPDParser; + +struct CPDPrinter +{ + const char* id; + const char* name; + const char* info; + const char* location; + const char* make_and_model; + const char* printer_state; + const char* backend_name; + bool is_accepting_jobs; + GDBusProxy* backend; +}; + +class CPDManager : public PrinterInfoManager +{ +#if ENABLE_DBUS && ENABLE_GIO + GDBusConnection * m_pConnection = nullptr; + bool m_aPrintersChanged = true; + std::vector> m_tBackends; + std::unordered_map< std::string, GDBusProxy * > m_pBackends; + std::unordered_map< FILE*, OString, FPtrHash > m_aSpoolFiles; + std::unordered_map< OUString, CPDPrinter * > m_aCPDDestMap; + std::unordered_map< OUString, PPDContext > m_aDefaultContexts; +#endif + CPDManager(); + // Function called when CPDManager is destroyed + virtual ~CPDManager() override; + + virtual void initialize() override; + +#if ENABLE_DBUS && ENABLE_GIO + static void onNameAcquired(GDBusConnection *connection, const gchar* name, gpointer user_data); + static void onNameLost (GDBusConnection *, const gchar *name, gpointer); + static void printerAdded (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); + static void printerRemoved (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); + + static void getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, const OString& rJobName, int& rNumOptions, GVariant **arr ); +#endif + +public: +#if ENABLE_DBUS && ENABLE_GIO + // Functions involved in initialization + GDBusProxy* getProxy(const std::string& target); + void addBackend( std::pair< std::string, GDBusProxy * > pair ); + void addTempBackend(const std::pair& pair); + std::vector> const & getTempBackends() const; + void addNewPrinter( const OUString&, const OUString&, CPDPrinter * ); +#endif + + // Create CPDManager + static CPDManager* tryLoadCPD(); + + // Create a PPDParser for CPD Printers + const PPDParser* createCPDParser( const OUString& rPrinter ); + + // Functions related to printing + virtual FILE* startSpool( const OUString& rPrinterName, bool bQuickCommand ) override; + virtual bool endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber ) override; + virtual void setupJobContextData( JobData& rData ) override; + + // check if the printer configuration has changed + virtual bool checkPrintersChanged( bool bWait ) override; +}; + +} // namespace psp + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/vcl/inc/unx/cupsmgr.hxx b/vcl/inc/unx/cupsmgr.hxx new file mode 100644 index 000000000..9fd153938 --- /dev/null +++ b/vcl/inc/unx/cupsmgr.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CUPSMGR_HXX +#define INCLUDED_VCL_INC_UNX_CUPSMGR_HXX + +#include +#include +#include + +namespace psp +{ + +class PPDParser; + +struct FPtrHash +{ + size_t operator()(const FILE* pPtr) const + { return reinterpret_cast(pPtr); } +}; + +class CUPSManager : public PrinterInfoManager +{ + std::unordered_map< FILE*, OString, FPtrHash > m_aSpoolFiles; + int m_nDests; + void* m_pDests; + bool m_bNewDests; + std::unordered_map< OUString, int > m_aCUPSDestMap; + + std::unordered_map< OUString, PPDContext > m_aDefaultContexts; + + 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*/ + OString m_aPassword; + + osl::Mutex m_aCUPSMutex; + oslThread m_aDestThread; + + osl::Mutex m_aGetPPDMutex; + bool m_bPPDThreadRunning; + + CUPSManager(); + virtual ~CUPSManager() override; + + virtual void initialize() override; + + static void getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ); + void runDests(); + OString threadedCupsGetPPD(const char* pPrinter); +public: + static void runDestThread(void* pMgr); + + static CUPSManager* tryLoadCUPS(); + + /// wraps cupsGetPPD, so unlink after use ! + const PPDParser* createCUPSParser( const OUString& rPrinter ); + + const char* authenticateUser(); + + virtual FILE* startSpool( const OUString& rPrinterName, bool bQuickCommand ) override; + virtual bool endSpool( const OUString& rPrinterName, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner, const OUString& rFaxNumber ) override; + virtual void setupJobContextData( JobData& rData ) override; + + /// check if the printer configuration has changed + virtual bool checkPrintersChanged( bool bWait ) override; +}; + +} // namespace psp + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/desktops.hxx b/vcl/inc/unx/desktops.hxx new file mode 100644 index 000000000..531e4c642 --- /dev/null +++ b/vcl/inc/unx/desktops.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_DESKTOPS_HXX +#define INCLUDED_VCL_INC_UNX_DESKTOPS_HXX + +#include + +#include + +enum SAL_DLLPUBLIC_RTTI DesktopType { + DESKTOP_NONE, // headless, i.e. no X connection at all + DESKTOP_UNKNOWN, // unknown desktop, simple WM, etc. + DESKTOP_GNOME, + DESKTOP_UNITY, + DESKTOP_XFCE, + DESKTOP_MATE, + DESKTOP_PLASMA5, + DESKTOP_LXQT +}; // keep in sync with desktop_strings[] in salplug.cxx + +#endif // INCLUDED_VCL_INC_UNX_DESKTOPS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/fc_fontoptions.hxx b/vcl/inc/unx/fc_fontoptions.hxx new file mode 100644 index 000000000..de6ed2aba --- /dev/null +++ b/vcl/inc/unx/fc_fontoptions.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_FC_FONTOPTIONS_HXX +#define INCLUDED_VCL_INC_UNX_FC_FONTOPTIONS_HXX + +#include + +typedef struct _FcPattern FcPattern; +class VCL_DLLPUBLIC FontConfigFontOptions +{ +public: + FontConfigFontOptions(FcPattern* pPattern) : + mpPattern(pPattern) {} + ~FontConfigFontOptions(); + + void SyncPattern(const OString& rFileName, sal_uInt32 nFontFace, sal_uInt32 nFontVariation, bool bEmbolden); + FcPattern* GetPattern() const; + static void cairo_font_options_substitute(FcPattern* pPattern); +private: + FcPattern* mpPattern; +}; + + +#endif // INCLUDED_VCL_INC_UNX_FC_FONTOPTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/fontmanager.hxx b/vcl/inc/unx/fontmanager.hxx new file mode 100644 index 000000000..7d625555d --- /dev/null +++ b/vcl/inc/unx/fontmanager.hxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_FONTMANAGER_HXX +#define INCLUDED_VCL_INC_FONTMANAGER_HXX + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * some words on metrics: every length returned by PrintFontManager and + * friends are PostScript afm style, that is they are 1/1000 font height + */ + +class FontSubsetInfo; +class FontConfigFontOptions; +class FontSelectPattern; +class GenericUnixSalData; + +namespace psp { +class PPDParser; + +typedef int fontID; + +/* + * the difference between FastPrintFontInfo and PrintFontInfo + * is that the information in FastPrintFontInfo can usually + * be gathered without opening either the font 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 + + // font attributes + OUString m_aFamilyName; + OUString m_aStyleName; + std::vector< OUString > m_aAliases; + FontFamily m_eFamilyStyle; + FontItalic m_eItalic; + FontWidth m_eWidth; + FontWeight m_eWeight; + FontPitch m_ePitch; + rtl_TextEncoding m_aEncoding; + + FastPrintFontInfo() + : m_nID(0) + , m_eFamilyStyle(FAMILY_DONTKNOW) + , m_eItalic(ITALIC_DONTKNOW) + , m_eWidth(WIDTH_DONTKNOW) + , m_eWeight(WEIGHT_DONTKNOW) + , m_ePitch(PITCH_DONTKNOW) + , m_aEncoding(RTL_TEXTENCODING_DONTKNOW) + {} +}; + +struct PrintFontInfo : public FastPrintFontInfo +{ + int m_nAscend; + int m_nDescend; + + PrintFontInfo() : + FastPrintFontInfo(), + m_nAscend( 0 ), + m_nDescend( 0 ) + {} +}; + +// a class to manage printable fonts + +class VCL_PLUGIN_PUBLIC PrintFontManager +{ + struct PrintFont; + friend struct PrintFont; + + struct VCL_DLLPRIVATE PrintFont + { + // font attributes + OUString m_aFamilyName; + std::vector m_aAliases; + OUString m_aPSName; + OUString m_aStyleName; + FontFamily m_eFamilyStyle; + FontItalic m_eItalic; + FontWidth m_eWidth; + FontWeight m_eWeight; + FontPitch m_ePitch; + rtl_TextEncoding m_aEncoding; + int m_nAscend; + int m_nDescend; + int m_nLeading; + int m_nXMin; // font bounding box + int m_nYMin; + int m_nXMax; + int m_nYMax; + + int m_nDirectory; // atom containing system dependent path + OString m_aFontFile; // relative to directory + int m_nCollectionEntry; // 0 for regular fonts, 0 to ... for fonts stemming from collections + int m_nVariationEntry; // 0 for regular fonts, 0 to ... for fonts stemming from font variations + + explicit PrintFont(); + }; + + fontID m_nNextFontID; + std::unordered_map< fontID, std::unique_ptr > m_aFonts; + // for speeding up findFontFileID + std::unordered_map< OString, std::set< fontID > > + m_aFontFileToFontID; + + std::unordered_map< OString, int > + m_aDirToAtom; + std::unordered_map< int, OString > m_aAtomToDir; + int m_nNextDirAtom; + + OString getFontFile(const PrintFont* pFont) const; + + std::vector> analyzeFontFile(int nDirID, const OString& rFileName, const char *pFormat=nullptr) const; + static OUString convertSfntName( void* pNameRecord ); // actually a NameRecord* format font subsetting code + static void analyzeSfntFamilyName( void const * pTTFont, std::vector< OUString >& rnames ); // actually a TrueTypeFont* from font subsetting code + bool analyzeSfntFile(PrintFont* pFont) const; + // finds the font id for the nFaceIndex face in this font file + // There may be multiple font ids for font collections + fontID findFontFileID(int nDirID, const OString& rFile, int nFaceIndex, int nVariationIndex) const; + + // There may be multiple font ids for font collections + std::vector findFontFileIDs( int nDirID, const OString& rFile ) const; + + static FontFamily matchFamilyName( const OUString& rFamily ); + + PrintFont* getFont( fontID nID ) const + { + auto it = m_aFonts.find( nID ); + return it == m_aFonts.end() ? nullptr : it->second.get(); + } + static void fillPrintFontInfo(PrintFont* pFont, FastPrintFontInfo& rInfo); + void fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const; + + OString getDirectory( int nAtom ) const; + int getDirectoryAtom( const OString& rDirectory ); + + /* try to initialize fonts from libfontconfig + + called from initialize() + */ + static void initFontconfig(); + void countFontconfigFonts( std::unordered_map& o_rVisitedPaths ); + /* deinitialize fontconfig + */ + static 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 + */ + static void addFontconfigDir(const OString& rDirectory); + + std::set m_aPreviousLangSupportRequests; + std::vector m_aCurrentRequests; + Timer m_aFontInstallerTimer; + + DECL_LINK( autoInstallFontLangSupport, Timer*, void ); + PrintFontManager(); +public: + ~PrintFontManager(); + friend class ::GenericUnixSalData; + static PrintFontManager& get(); // one instance only + + // There may be multiple font ids for font collections + std::vector addFontFile( const OUString& rFileUrl ); + + void initialize(); + + // returns the ids of all managed fonts. + void getFontList( std::vector< fontID >& rFontIDs ); + + // 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 PSName name + OUString getPSName( fontID nFontID ) const; + + // get a specific fonts italic type + FontItalic getFontItalic( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eItalic : ITALIC_DONTKNOW; + } + + // get a specific fonts weight type + FontWeight getFontWeight( fontID nFontID ) const + { + PrintFont* pFont = getFont( nFontID ); + return pFont ? pFont->m_eWeight : WEIGHT_DONTKNOW; + } + + // get a specific fonts system dependent filename + OString getFontFileSysPath( fontID nFontID ) const + { + return getFontFile( getFont( nFontID ) ); + } + + // get the ttc face number + int getFontFaceNumber( fontID nFontID ) const; + + // get the ttc face variation + int getFontFaceVariation( fontID nFontID ) const; + + // get a specific fonts ascend + int getFontAscend( fontID nFontID ) const; + + // get a specific fonts descent + int getFontDescend( fontID nFontID ) const; + + // get a fonts glyph bounding box + void getFontBoundingBox( fontID nFont, int& xMin, int& yMin, int& xMax, int& yMax ); + + // creates a new font subset of an existing SFNT 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 OUString& rOutFile, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pNewEncoding, + sal_Int32* pWidths, + int nGlyphs + ); + void getGlyphWidths( fontID nFont, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc ); + + // font administration functions + + /* system dependent font matching + +

+ matchFont matches a pattern of font characteristics + and returns the closest match if possible. If a match was found + the FastPrintFontInfo passed in as parameter + will be update to the found matching font. +

+

+ implementation note: currently the function is only implemented + for fontconfig. +

+ + @param rInfo + out of the FastPrintFontInfo structure the following + fields will be used for the match: +
    +
  • family name
  • +
  • italic
  • +
  • width
  • +
  • weight
  • +
  • pitch
  • +
+ + @param rLocale + if rLocal 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 + */ + void matchFont( FastPrintFontInfo& rInfo, const css::lang::Locale& rLocale ); + static std::unique_ptr getFontOptions( const FastPrintFontInfo&, int nSize); + + void Substitute(FontSelectPattern &rPattern, OUString& rMissingCodes); + +}; + +} // namespace + +#endif // INCLUDED_VCL_INC_FONTMANAGER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx new file mode 100644 index 000000000..c375ba2ff --- /dev/null +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_GENERIC_GLYPHS_GCACH_FTYP_HXX +#define INCLUDED_VCL_GENERIC_GLYPHS_GCACH_FTYP_HXX + +#include +#include +#include +#include + +class CmapResult; + +// FreetypeFontFile 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 FreetypeFontFile final +{ +public: + bool Map(); + void Unmap(); + + const unsigned char* GetBuffer() const { return mpFileMap; } + int GetFileSize() const { return mnFileSize; } + const OString& GetFileName() const { return maNativeFileName; } + int GetLangBoost() const { return mnLangBoost; } + +private: + friend class FreetypeManager; + explicit FreetypeFontFile( const OString& rNativeFileName ); + + const OString maNativeFileName; + unsigned char* mpFileMap; + int mnFileSize; + int mnRefCount; + int mnLangBoost; +}; + +// FreetypeFontInfo corresponds to an unscaled font face +class FreetypeFontInfo final +{ +public: + ~FreetypeFontInfo(); + + const unsigned char* GetTable( const char*, sal_uLong* pLength) const; + + FT_FaceRec_* GetFaceFT(); + void ReleaseFaceFT(); + + const OString& GetFontFileName() const { return mpFontFile->GetFileName(); } + int GetFontFaceIndex() const { return mnFaceNum; } + int GetFontFaceVariation() const { return mnFaceVariation; } + sal_IntPtr GetFontId() const { return mnFontId; } + bool IsSymbolFont() const { return maDevFontAttributes.IsSymbolFont(); } + const FontAttributes& GetFontAttributes() const { return maDevFontAttributes; } + + void AnnounceFont( PhysicalFontCollection* ); + + const FontCharMapRef& GetFontCharMap(); + +private: + friend class FreetypeManager; + explicit FreetypeFontInfo(const FontAttributes&, FreetypeFontFile* const pFontFile, + int nFaceNum, int nFaceVariation, sal_IntPtr nFontId); + + FT_FaceRec_* maFaceFT; + FreetypeFontFile* const mpFontFile; + const int mnFaceNum; + const int mnFaceVariation; + int mnRefCount; + sal_IntPtr mnFontId; + FontAttributes maDevFontAttributes; + + FontCharMapRef mxFontCharMap; +}; + +class FreetypeFontFace : public PhysicalFontFace +{ +private: + FreetypeFontInfo* mpFreetypeFontInfo; + +public: + FreetypeFontFace( FreetypeFontInfo*, const FontAttributes& ); + + virtual rtl::Reference CreateFontInstance( const FontSelectPattern& ) const override; + virtual sal_IntPtr GetFontId() const override { return mpFreetypeFontInfo->GetFontId(); } +}; + +class SAL_DLLPUBLIC_RTTI FreetypeFontInstance : public LogicalFontInstance +{ + friend rtl::Reference FreetypeFontFace::CreateFontInstance(const FontSelectPattern&) const; + + std::unique_ptr mxFreetypeFont; + + virtual hb_font_t* ImplInitHbFont() override; + virtual bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; + +protected: + explicit FreetypeFontInstance(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP); + +public: + virtual ~FreetypeFontInstance() override; + + FreetypeFont& GetFreetypeFont() const { return *mxFreetypeFont; } + + virtual bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; +}; + +#endif // INCLUDED_VCL_GENERIC_GLYPHS_GCACH_FTYP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/freetypetextrender.hxx b/vcl/inc/unx/freetypetextrender.hxx new file mode 100644 index 000000000..ccc1db015 --- /dev/null +++ b/vcl/inc/unx/freetypetextrender.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_FREETYPETEXTRENDER_HXX +#define INCLUDED_VCL_INC_UNX_FREETYPETEXTRENDER_HXX + +#include + +class FreetypeFontInstance; + +// Generic implementation that uses freetype, but DrawTextLayout() +// still needs implementing (e.g. by Cairo or Skia). +class VCL_DLLPUBLIC FreeTypeTextRenderImpl : public TextRenderImpl +{ +protected: + rtl::Reference + mpFreetypeFont[ MAX_FALLBACK ]; + + Color mnTextColor; + +public: + FreeTypeTextRenderImpl(); + virtual ~FreeTypeTextRenderImpl() override; + + virtual void SetTextColor( Color nColor ) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const override; + virtual void GetDevFontList( PhysicalFontCollection* ) override; + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) override; + virtual bool CreateFontSubset( + const OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo) override; + + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + virtual void GetGlyphWidths( + const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; +#if ENABLE_CAIRO_CANVAS + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const override; +#endif +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gendata.hxx b/vcl/inc/unx/gendata.hxx new file mode 100644 index 000000000..f06dda35c --- /dev/null +++ b/vcl/inc/unx/gendata.hxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENDATA_HXX +#define INCLUDED_VCL_INC_GENERIC_GENDATA_HXX + +#include + +#include + +#include + +class FreetypeManager; +class SalGenericDisplay; +namespace psp +{ +class PrintFontManager; +} + +enum GenericUnixSalDataType +{ + SAL_DATA_GTK, + SAL_DATA_GTK3, + SAL_DATA_KF5, + SAL_DATA_UNX, + SAL_DATA_SVP, + SAL_DATA_ANDROID, + SAL_DATA_IOS, + SAL_DATA_HEADLESS, + SAL_DATA_QT5 +}; + +class VCL_DLLPUBLIC GenericUnixSalData : public SalData +{ +private: + GenericUnixSalDataType m_eType; + SalGenericDisplay* m_pDisplay; + // cached hostname to avoid slow lookup + OUString m_aHostname; + // for transient storage of unicode strings eg. 'u123' by input methods + OUString m_aUnicodeEntry; + + std::unique_ptr m_pFreetypeManager; + std::unique_ptr m_pPrintFontManager; + + void InitFreetypeManager(); + void InitPrintFontManager(); + +public: + GenericUnixSalData(GenericUnixSalDataType const t, SalInstance* const pInstance); + virtual ~GenericUnixSalData() override; + virtual void Dispose() {} + + SalGenericDisplay* GetDisplay() const { return m_pDisplay; } + void SetDisplay(SalGenericDisplay* pDisp) { m_pDisplay = pDisp; } + + const OUString& GetHostname() + { + if (m_aHostname.isEmpty()) + osl_getLocalHostname(&m_aHostname.pData); + return m_aHostname; + } + + OUString& GetUnicodeCommand() { return m_aUnicodeEntry; } + + GenericUnixSalDataType GetType() const { return m_eType; } + + FreetypeManager* GetFreetypeManager() + { + if (!m_pFreetypeManager) + InitFreetypeManager(); + return m_pFreetypeManager.get(); + } + + psp::PrintFontManager* GetPrintFontManager() + { + if (!m_pPrintFontManager) + InitPrintFontManager(); + // PrintFontManager needs the FreetypeManager + assert(m_pFreetypeManager); + return m_pPrintFontManager.get(); + } + + // Mostly useful for remote protocol backends + virtual void ErrorTrapPush() = 0; + virtual bool ErrorTrapPop(bool bIgnoreError = true) = 0; // true on error +}; + +inline GenericUnixSalData* GetGenericUnixSalData() +{ + return static_cast(ImplGetSVData()->mpSalData); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gendisp.hxx b/vcl/inc/unx/gendisp.hxx new file mode 100644 index 000000000..a6188e27a --- /dev/null +++ b/vcl/inc/unx/gendisp.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENDISP_HXX +#define INCLUDED_VCL_INC_GENERIC_GENDISP_HXX + +#include +#include +#include + +class SalFrame; +class VCL_DLLPUBLIC SalGenericDisplay : public SalUserEventList +{ +protected: + SalFrame* m_pCapture; + + virtual void ProcessEvent( SalUserEvent aEvent ) override; + +public: + SalGenericDisplay(); + virtual ~SalGenericDisplay() override; + + void registerFrame( SalFrame* pFrame ); + virtual void deregisterFrame( SalFrame* pFrame ); + void emitDisplayChanged(); + + void SendInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent = SalEvent::UserEvent ); + void CancelInternalEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ); + bool DispatchInternalEvent( bool bHandleAllCurrentEvent = false ); + + bool MouseCaptured( const SalFrame *pFrameData ) const + { return m_pCapture == pFrameData; } + SalFrame* GetCaptureFrame() const + { return m_pCapture; } +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GENDISP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/geninst.h b/vcl/inc/unx/geninst.h new file mode 100644 index 000000000..dcd8bdd6f --- /dev/null +++ b/vcl/inc/unx/geninst.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENINST_H +#define INCLUDED_VCL_INC_GENERIC_GENINST_H + +#include +#include +#include +#include +#include + +class VCL_DLLPUBLIC SalYieldMutex : public comphelper::SolarMutex +{ +public: + SalYieldMutex(); + virtual ~SalYieldMutex() override; +}; + +/* + * Abstract generic class to build vclplugin's instance classes from + */ +class GenPspGraphics; +class PhysicalFontCollection; +class VCL_DLLPUBLIC SalGenericInstance : public SalInstance +{ +protected: + bool mbPrinterInit; + +public: + SalGenericInstance( std::unique_ptr pMutex ) + : SalInstance(std::move(pMutex)), mbPrinterInit(false) {} + virtual ~SalGenericInstance() override; + + // Printing + virtual SalInfoPrinter* CreateInfoPrinter ( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) override; + virtual void DestroyInfoPrinter ( SalInfoPrinter* pPrinter ) override; + virtual std::unique_ptr CreatePrinter ( SalInfoPrinter* pInfoPrinter ) override; + virtual void GetPrinterQueueInfo ( ImplPrnQueueList* pList ) override; + virtual void GetPrinterQueueState ( SalPrinterQueueInfo* pInfo ) override; + virtual OUString GetDefaultPrinter() override; + virtual void PostPrintersChanged() = 0; + virtual void updatePrinterUpdate() override; + virtual void jobStartedPrinterUpdate() override; + virtual void jobEndedPrinterUpdate() override; + bool isPrinterInit() const { return mbPrinterInit; } + virtual std::unique_ptr CreatePrintGraphics() = 0; + + virtual OUString getOSVersion() override; + + // prolly belongs somewhere else ... just a font help + static void RegisterFontSubstitutors( PhysicalFontCollection* pFontCollection ); + +protected: + static void configurePspInfoPrinter( PspSalInfoPrinter* pInfoPrinter, + SalPrinterQueueInfo const * pQueueInfo, + ImplJobSetup* pSetupData ); +}; + +inline SalGenericInstance *GetGenericInstance() +{ + return static_cast(GetSalData()->m_pInstance); +} + +#endif // INCLUDED_VCL_INC_GENERIC_GENINST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/genprn.h b/vcl/inc/unx/genprn.h new file mode 100644 index 000000000..14917cf72 --- /dev/null +++ b/vcl/inc/unx/genprn.h @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENPRN_H +#define INCLUDED_VCL_INC_GENERIC_GENPRN_H + +#include +#include +#include +#include + +class GenPspGraphics; +class VCL_DLLPUBLIC PspSalInfoPrinter : public SalInfoPrinter +{ +public: + std::unique_ptr m_pGraphics; + psp::JobData m_aJobData; + psp::PrinterGfx m_aPrinterGfx; + + PspSalInfoPrinter(); + virtual ~PspSalInfoPrinter() override; + + // override all pure virtual methods + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool Setup( weld::Window* pFrame, ImplJobSetup* pSetupData ) override; + virtual bool SetPrinterData( ImplJobSetup* pSetupData ) override; + virtual bool SetData( JobSetFlags nFlags, ImplJobSetup* pSetupData ) override; + virtual void GetPageInfo( const ImplJobSetup* pSetupData, + long& rOutWidth, long& rOutHeight, + Point& rPageOffset, + Size& rPaperSize ) override; + virtual sal_uInt32 GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType ) override; + virtual sal_uInt16 GetPaperBinCount( const ImplJobSetup* pSetupData ) override; + virtual OUString GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin ) override; + virtual void InitPaperFormats( const ImplJobSetup* pSetupData ) override; + virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ) override; +}; + +class VCL_DLLPUBLIC PspSalPrinter : public SalPrinter +{ +public: + OUString m_aFileName; + OUString m_aTmpFile; + SalInfoPrinter* m_pInfoPrinter; + std::unique_ptr m_xGraphics; + psp::PrinterJob m_aPrintJob; + psp::JobData m_aJobData; + psp::PrinterGfx m_aPrinterGfx; + sal_uInt32 m_nCopies; + bool m_bCollate; + bool m_bPdf; + bool m_bIsPDFWriterJob; + + PspSalPrinter( SalInfoPrinter *pPrinter ); + virtual ~PspSalPrinter() override; + + // override all pure virtual methods + virtual bool StartJob( const OUString* pFileName, + const OUString& rJobName, + const OUString& rAppName, + sal_uInt32 nCopies, + bool bCollate, + bool bDirect, + ImplJobSetup* pSetupData ) override; + virtual bool StartJob( const OUString*, + const OUString&, + const OUString&, + ImplJobSetup*, + vcl::PrinterController& i_rController ) override; + virtual bool EndJob() override; + virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, bool bNewJobData ) override; + virtual void EndPage() override; +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GENPRN_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h new file mode 100644 index 000000000..b696618c7 --- /dev/null +++ b/vcl/inc/unx/genpspgraphics.h @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENPSPGRAPHICS_H +#define INCLUDED_VCL_INC_GENERIC_GENPSPGRAPHICS_H + +#include +#include + +#include +#include +#include + +class PhysicalFontFace; +class PhysicalFontCollection; + +namespace psp { struct JobData; class PrinterGfx; } + +class FreetypeFontInstance; +class FontAttributes; +class SalInfoPrinter; +class ImplFontMetricData; + +class VCL_DLLPUBLIC GenPspGraphics final : public SalGraphics +{ + psp::JobData* m_pJobData; + psp::PrinterGfx* m_pPrinterGfx; + + rtl::Reference + m_pFreetypeFont[ MAX_FALLBACK ]; +public: + GenPspGraphics(); + virtual ~GenPspGraphics() override; + + void Init( psp::JobData* pJob, psp::PrinterGfx* pGfx ); + + // helper methods + static const void * DoGetEmbedFontData(psp::fontID aFont, long* pDataLen); + static void DoFreeEmbedFontData( const void* pData, long nLen ); + + // helper methods for sharing with X11SalGraphics + static void DoGetGlyphWidths( psp::fontID aFont, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ); + + static FontAttributes Info2FontAttributes( const psp::FastPrintFontInfo& ); + static void AnnounceFonts( PhysicalFontCollection*, + const psp::FastPrintFontInfo& ); + + // override all pure virtual methods + virtual SalGraphicsImpl*GetImpl() const override { return nullptr; }; + virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override; + virtual sal_uInt16 GetBitCount() const override; + virtual long GetGraphicsWidth() const override; + + virtual void ResetClipRegion() override; + virtual bool setClipRegion( const vcl::Region& ) override; + + virtual void SetLineColor() override; + virtual void SetLineColor( Color nColor ) override; + virtual void SetFillColor() override; + virtual void SetFillColor( Color nColor ) override; + virtual void SetXORMode( bool bSet, bool ) override; + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + + virtual void SetTextColor( Color nColor ) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const override; + virtual void GetDevFontList( PhysicalFontCollection* ) override; + // graphics must drop any cached font info + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, + const OUString& rFileURL, + const OUString& rFontName ) override; + static bool AddTempDevFontHelper( PhysicalFontCollection* pFontCollection, + const OUString& rFileURL, + const OUString& rFontName); + + virtual bool CreateFontSubset( const OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo ) override; + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout( const GenericSalLayout& ) override; + virtual bool supportsOperation( OutDevSupportType ) const override; + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolyPolygon( sal_uInt32 nPoly, + const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + virtual bool drawPolyLineBezier( sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + virtual bool drawPolygonBezier( sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) override; + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + + virtual void copyArea( long nDestX, + long nDestY, + long nSrcX, + long nSrcY, + long nSrcWidth, + long nSrcHeight, + bool bWindowInvalidate) override; + virtual void copyBits( const SalTwoRect& rPosAry, + SalGraphics* pSrcGraphics ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) override; + virtual void drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + virtual Color getPixel( long nX, long nY ) override; + virtual void invert( long nX, long nY, long nWidth, long nHeight, + SalInvert nFlags ) override; + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, + SalInvert nFlags ) override; + + virtual bool drawEPS( long nX, long nY, long nWidth, long nHeight, + void* pPtr, sal_uInt32 nSize ) override; + virtual bool blendBitmap( const SalTwoRect&, + const SalBitmap& rBitmap ) override; + virtual bool blendAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + virtual bool drawAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) override; + virtual bool drawTransformedBitmap( const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, + sal_uInt8 nTransparency ) override; + + virtual SystemGraphicsData GetGraphicsData() const override; + + virtual OUString getRenderBackendName() const override { return "genpsp"; } + +#if ENABLE_CAIRO_CANVAS + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override; + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override; + + virtual SystemFontData GetSysFontData( int nFallbacklevel ) const override; +#endif // ENABLE_CAIRO_CANVAS +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GENPSPGRAPHICS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gensys.h b/vcl/inc/unx/gensys.h new file mode 100644 index 000000000..6da0b17b8 --- /dev/null +++ b/vcl/inc/unx/gensys.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GENSYS_H +#define INCLUDED_VCL_INC_GENERIC_GENSYS_H + +#include +#include + +/* + * Helps de-tangle the rather horrible ShowNativeMessageBox API + */ +class VCL_DLLPUBLIC SalGenericSystem : public SalSystem +{ + public: + SalGenericSystem(); + virtual ~SalGenericSystem() override; + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) = 0; + + virtual int ShowNativeMessageBox( const OUString& rTitle, + const OUString& rMessage) override; + +#if !defined(ANDROID) && !defined(IOS) + // Simple helpers for X11 WM_CLASS hints + static const char *getFrameResName(); + static const char *getFrameClassName(); +#endif +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GENSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx new file mode 100644 index 000000000..983a6ec03 --- /dev/null +++ b/vcl/inc/unx/glyphcache.hxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX +#define INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX + +#include +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +class FreetypeFont; +class FreetypeFontFile; +class FreetypeFontInstance; +class FreetypeFontInfo; +class FontConfigFontOptions; +class PhysicalFontCollection; +class FreetypeFont; +class SvpGcpHelper; + +namespace basegfx { class B2DPolyPolygon; } +namespace vcl { struct FontCapabilities; } + + /** + * The FreetypeManager caches various aspects of Freetype fonts + * + * It mainly consists of two std::unordered_map lists, which hold the items of the cache. + * + * They form kind of a tree, with FreetypeFontFile as the roots, referenced by multiple FreetypeFontInfo + * entries, which are referenced by the FreetypeFont items. + * + * All of these items have reference counters, but these don't control the items life-cycle, but that of + * the managed resources. + * + * The respective resources are: + * FreetypeFontFile = holds the mmapped font file, as long as it's used by any FreetypeFontInfo. + * FreetypeFontInfo = holds the FT_FaceRec_ object, as long as it's used by any FreetypeFont. + * FreetypeFont = holds the FT_SizeRec_ and is owned by a FreetypeFontInstance + * + * FreetypeFontInfo therefore is embedded in the Freetype subclass of PhysicalFontFace. + * FreetypeFont is owned by FreetypeFontInstance, the Freetype subclass of LogicalFontInstance. + * + * Nowadays there is not really a reason to have separate files for the classes, as the FreetypeManager + * is just about handling of Freetype based fonts, not some abstract glyphs. + **/ +class VCL_DLLPUBLIC FreetypeManager final +{ +public: + ~FreetypeManager(); + + static FreetypeManager& get(); + + void AddFontFile(const OString& rNormalizedName, + int nFaceNum, int nVariantNum, + sal_IntPtr nFontId, + const FontAttributes&); + + void AnnounceFonts( PhysicalFontCollection* ) const; + + void ClearFontCache(); + + FreetypeFont* CreateFont(FreetypeFontInstance* pLogicalFont); + +private: + // to access the constructor (can't use InitFreetypeManager function, because it's private?!) + friend class GenericUnixSalData; + explicit FreetypeManager(); + + static void InitFreetype(); + FreetypeFontFile* FindFontFile(const OString& rNativeFileName); + + typedef std::unordered_map> FontInfoList; + typedef std::unordered_map, rtl::CStringHash, rtl::CStringEqual> FontFileList; + + FontInfoList m_aFontInfoList; + sal_IntPtr m_nMaxFontId; + + FontFileList m_aFontFileList; +}; + +class VCL_DLLPUBLIC FreetypeFont final +{ +public: + ~FreetypeFont(); + + const OString& GetFontFileName() const; + int GetFontFaceIndex() const; + int GetFontFaceVariation() const; + bool TestFont() const { return mbFaceOk;} + FT_Face GetFtFace() const; + int GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); } + const FontConfigFontOptions* GetFontOptions() const; + bool NeedsArtificialBold() const { return mbArtBold; } + bool NeedsArtificialItalic() const { return mbArtItalic; } + + void GetFontMetric(ImplFontMetricDataRef const &) const; + const unsigned char* GetTable( const char* pName, sal_uLong* pLength ) const; + FontCharMapRef GetFontCharMap() const; + bool GetFontCapabilities(vcl::FontCapabilities &) const; + + bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const; + bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const; + bool GetAntialiasAdvice() const; + + FreetypeFontInstance& GetFontInstance() const { return mrFontInstance; } + + void SetFontVariationsOnHBFont(hb_font_t* pHbFace) const; + + // tdf#127189 FreeType <= 2.8 will fail to render stretched horizontal brace glyphs + // in starmath at a fairly low stretch ratio. This appears fixed in 2.9 with + // https://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=91015cb41d8f56777f93394f5a60914bc0c0f330 + // "Improve complex rendering at high ppem" + static bool AlmostHorizontalDrainsRenderingPool(int nRatio, const FontSelectPattern& rFSD); + +private: + friend class FreetypeFontInstance; + friend class FreetypeManager; + + explicit FreetypeFont(FreetypeFontInstance&, std::shared_ptr& rFontInfo); + + void ApplyGlyphTransform(bool bVertical, FT_Glyph) const; + + FreetypeFontInstance& mrFontInstance; + + // 16.16 fixed point values used for a rotated font + long mnCos; + long mnSin; + + int mnWidth; + int mnPrioAntiAlias; + std::shared_ptr mxFontInfo; + FT_Int mnLoadFlags; + double mfStretch; + FT_FaceRec_* maFaceFT; + FT_SizeRec_* maSizeFT; + + mutable std::unique_ptr mxFontOptions; + + bool mbFaceOk; + bool mbArtItalic; + bool mbArtBold; +}; + +#endif // INCLUDED_VCL_INC_GENERIC_GLYPHCACHE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gstsink.hxx b/vcl/inc/unx/gstsink.hxx new file mode 100644 index 000000000..2dff94b02 --- /dev/null +++ b/vcl/inc/unx/gstsink.hxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include + +#if ENABLE_GSTREAMER_1_0 +#include +#include + +typedef GstElement* (*GstElementFactoryName)(const gchar*, const gchar*); + +static GstElementFactoryName gstElementFactoryNameSymbol() +{ + return reinterpret_cast(dlsym(nullptr, "gst_element_factory_make")); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/atkbridge.hxx b/vcl/inc/unx/gtk/atkbridge.hxx new file mode 100644 index 000000000..49c422dac --- /dev/null +++ b/vcl/inc/unx/gtk/atkbridge.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_ATKBRIDGE_HXX +#define INCLUDED_VCL_INC_UNX_GTK_ATKBRIDGE_HXX + +#include + +bool InitAtkBridge(); +void DeInitAtkBridge(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gloactiongroup.h b/vcl/inc/unx/gtk/gloactiongroup.h new file mode 100644 index 000000000..4028f76dc --- /dev/null +++ b/vcl/inc/unx/gtk/gloactiongroup.h @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GLOACTIONGROUP_H +#define INCLUDED_VCL_INC_UNX_GTK_GLOACTIONGROUP_H + +#include +#include + +G_BEGIN_DECLS + +#define G_TYPE_LO_ACTION_GROUP (g_lo_action_group_get_type ()) +#define G_LO_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_LO_ACTION_GROUP, GLOActionGroup)) +#define G_IS_LO_ACTION_GROUP(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_LO_ACTION_GROUP)) + +struct GLOActionGroupPrivate; + +struct GLOActionGroup +{ + /*< private >*/ + GObject parent_instance; + + GLOActionGroupPrivate *priv; +}; + +struct GLOActionGroupClass +{ + /*< private >*/ + GObjectClass parent_class; + + /*< private >*/ + gpointer padding[12]; +}; + +GType g_lo_action_group_get_type (void) G_GNUC_CONST; + +GLOActionGroup * g_lo_action_group_new (void); + +void g_lo_action_group_set_top_menu (GLOActionGroup *group, + gpointer top_menu); + +void g_lo_action_group_insert (GLOActionGroup *group, + const gchar *action_name, + gint item_id, + gboolean submenu); + +void g_lo_action_group_insert_stateful (GLOActionGroup *group, + const gchar *action_name, + gint item_id, + gboolean submenu, + const GVariantType *parameter_type, + const GVariantType *state_type, + GVariant *state_hint, + GVariant *state); + +void g_lo_action_group_set_action_enabled (GLOActionGroup *group, + const gchar *action_name, + gboolean enabled); + +void g_lo_action_group_remove (GLOActionGroup *group, + const gchar *action_name); + +void g_lo_action_group_clear (GLOActionGroup *group); + +G_END_DECLS + +#endif // INCLUDED_VCL_INC_UNX_GTK_GLOACTIONGROUP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/glomenu.h b/vcl/inc/unx/gtk/glomenu.h new file mode 100644 index 000000000..a0150a845 --- /dev/null +++ b/vcl/inc/unx/gtk/glomenu.h @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GLOMENU_H +#define INCLUDED_VCL_INC_UNX_GTK_GLOMENU_H + +#include + +#define G_LO_MENU_ATTRIBUTE_ACCELERATOR "accel" +#define G_LO_MENU_ATTRIBUTE_COMMAND "command" +#define G_LO_MENU_ATTRIBUTE_SUBMENU_ACTION "submenu-action" + +G_BEGIN_DECLS + +#define G_TYPE_LO_MENU (g_lo_menu_get_type ()) +#define G_LO_MENU(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_LO_MENU, GLOMenu)) +#define G_IS_LO_MENU(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_LO_MENU)) + +struct GLOMenu; + +class GtkSalMenuItem; + +GLIB_AVAILABLE_IN_2_32 +GType g_lo_menu_get_type (void) G_GNUC_CONST; +GLIB_AVAILABLE_IN_2_32 +GLOMenu * g_lo_menu_new (void); + +gint g_lo_menu_get_n_items_from_section (GLOMenu *menu, + gint section); + +void g_lo_menu_insert (GLOMenu *menu, + gint position, + const gchar *label); + +void g_lo_menu_insert_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *label); + +void g_lo_menu_new_section (GLOMenu *menu, + gint position, + const gchar *label); + +void g_lo_menu_insert_section (GLOMenu *menu, + gint position, + const gchar *label, + GMenuModel *section); + +GLOMenu * g_lo_menu_get_section (GLOMenu *menu, + gint section); + +void g_lo_menu_remove (GLOMenu *menu, + gint position); + +void g_lo_menu_remove_from_section (GLOMenu *menu, + gint section, + gint position); + +void g_lo_menu_set_label (GLOMenu *menu, + gint position, + const gchar *label); + +void g_lo_menu_set_icon (GLOMenu *menu, + gint position, + const GIcon *icon); + + +void g_lo_menu_set_label_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *label); + +void g_lo_menu_set_icon_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const GIcon *icon); + +gchar * g_lo_menu_get_label_from_item_in_section (GLOMenu *menu, + gint section, + gint position); + +void g_lo_menu_set_action_and_target_value (GLOMenu *menu, + gint position, + const gchar *command, + GVariant *target_value); + +void g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *command, + GVariant *target_value); + +void g_lo_menu_set_command_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *command); + +gchar * g_lo_menu_get_command_from_item_in_section (GLOMenu *menu, + gint section, + gint position); + +void g_lo_menu_set_accelerator_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *accelerator); + +gchar * g_lo_menu_get_accelerator_from_item_in_section (GLOMenu *menu, + gint section, + gint position); + +void g_lo_menu_new_submenu_in_item_in_section (GLOMenu *menu, + gint section, + gint position); + +GLOMenu * g_lo_menu_get_submenu_from_item_in_section (GLOMenu *menu, + gint section, + gint position); + +void g_lo_menu_set_submenu_action_to_item_in_section (GLOMenu *menu, + gint section, + gint position, + const gchar *action); + +G_END_DECLS + +#endif // INCLUDED_VCL_INC_UNX_GTK_GLOMENU_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkbackend.hxx b/vcl/inc/unx/gtk/gtkbackend.hxx new file mode 100644 index 000000000..288311b41 --- /dev/null +++ b/vcl/inc/unx/gtk/gtkbackend.hxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKBACKEND_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKBACKEND_HXX + +#include +#if defined(GDK_WINDOWING_X11) +#include +bool DLSYM_GDK_IS_X11_DISPLAY(GdkDisplay* pDisplay); +#endif +#if defined(GDK_WINDOWING_WAYLAND) +#include +bool DLSYM_GDK_IS_WAYLAND_DISPLAY(GdkDisplay* pDisplay); +#endif + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKBACKEND_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkdata.hxx b/vcl/inc/unx/gtk/gtkdata.hxx new file mode 100644 index 000000000..2f88ffe8b --- /dev/null +++ b/vcl/inc/unx/gtk/gtkdata.hxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKDATA_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKDATA_HXX + +#define GLIB_DISABLE_DEPRECATION_WARNINGS +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace com::sun::star::accessibility { class XAccessibleEventListener; } + +class GtkSalDisplay; +class DocumentFocusListener; + +inline ::Window widget_get_xid(GtkWidget *widget) +{ + return GDK_WINDOW_XID(gtk_widget_get_window(widget)); +} + +class GtkSalTimer final : public SalTimer +{ + struct SalGtkTimeoutSource *m_pTimeout; +public: + GtkSalTimer(); + virtual ~GtkSalTimer() override; + virtual void Start( sal_uInt64 nMS ) override; + virtual void Stop() override; + bool Expired(); + + sal_uLong m_nTimeoutMS; +}; + +class GtkSalData final : public GenericUnixSalData +{ + GSource* m_pUserEvent; + osl::Mutex m_aDispatchMutex; + osl::Condition m_aDispatchCondition; + std::exception_ptr m_aException; + + css::uno::Reference m_xDocumentFocusListener; + DocumentFocusListener * m_pDocumentFocusListener; + +public: + GtkSalData( SalInstance *pInstance ); + virtual ~GtkSalData() override; + + DocumentFocusListener & GetDocumentFocusListener(); + + void Init(); + virtual void Dispose() override; + + static void initNWF(); + static void deInitNWF(); + + void TriggerUserEventProcessing(); + void TriggerAllUserEventsProcessed(); + + bool Yield( bool bWait, bool bHandleAllCurrentEvents ); + inline GdkDisplay *GetGdkDisplay(); + + virtual void ErrorTrapPush() override; + virtual bool ErrorTrapPop( bool bIgnoreError = true ) override; + + inline GtkSalDisplay *GetGtkDisplay() const; + void setException(const std::exception_ptr& exception) { m_aException = exception; } +}; + +class GtkSalFrame; + +class GtkSalDisplay : public SalGenericDisplay +{ + GtkSalSystem* m_pSys; + GdkDisplay* m_pGdkDisplay; + o3tl::enumarray m_aCursors; + bool m_bStartupCompleted; + bool m_bX11Display; + + GdkCursor* getFromSvg( OUString const & name, int nXHot, int nYHot ); + +public: + GtkSalDisplay( GdkDisplay* pDisplay ); + virtual ~GtkSalDisplay() override; + + GdkDisplay* GetGdkDisplay() const { return m_pGdkDisplay; } + bool IsX11Display() const { return m_bX11Display; } + + GtkSalSystem* getSystem() const { return m_pSys; } + + GtkWidget* findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) const; + + virtual void deregisterFrame( SalFrame* pFrame ) override; + GdkCursor *getCursor( PointerStyle ePointerStyle ); + virtual int CaptureMouse( SalFrame* pFrame ); + + SalX11Screen GetDefaultXScreen() { return m_pSys->GetDisplayDefaultXScreen(); } + Size GetScreenSize( int nDisplayScreen ); + + GdkFilterReturn filterGdkEvent( GdkXEvent* sys_event ); + void startupNotificationCompleted() { m_bStartupCompleted = true; } + + void screenSizeChanged( GdkScreen const * ); + void monitorsChanged( GdkScreen const * ); + + virtual void TriggerUserEventProcessing() override; + virtual void TriggerAllUserEventsProcessed() override; +}; + +inline GtkSalData* GetGtkSalData() +{ + return static_cast(ImplGetSVData()->mpSalData); +} +inline GdkDisplay *GtkSalData::GetGdkDisplay() +{ + return GetGtkDisplay()->GetGdkDisplay(); +} + +GtkSalDisplay *GtkSalData::GetGtkDisplay() const +{ + return static_cast(GetDisplay()); +} + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx new file mode 100644 index 000000000..e42e1649a --- /dev/null +++ b/vcl/inc/unx/gtk/gtkframe.hxx @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKFRAME_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKFRAME_HXX + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +class GtkSalGraphics; +class GtkSalDisplay; + +typedef sal_uIntPtr GdkNativeWindow; +#define GDK_WINDOW_XWINDOW(o) GDK_WINDOW_XID(o) +#define gdk_set_sm_client_id(i) gdk_x11_set_sm_client_id(i) +#define gdk_window_foreign_new_for_display(a,b) gdk_x11_window_foreign_new_for_display(a,b) +class GtkDropTarget; +class GtkDragSource; +class GtkDnDTransferable; + +class GtkSalMenu; + +class GtkSalFrame final : public SalFrame + , public NativeWindowHandleProvider +{ + 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 (nullptr), + 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 const *event) const + { + return (event != nullptr) + && (event->window == window) + && (event->send_event == send_event) + // ignore non-Gdk state bits, e.g., these used by IBus + && ((event->state & GDK_MODIFIER_MASK) == (state & GDK_MODIFIER_MASK)) + && (event->keyval == keyval) + && (event->hardware_keycode == hardware_keycode) + && (event->group == group) + && (event->time - time < 300) + ; + } + }; + + 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< ExtTextInputAttr > m_aInputFlags; + + IMHandler( GtkSalFrame* ); + ~IMHandler(); + + void createIMContext(); + void deleteIMContext(); + void updateIMSpotLocation(); + void endExtTextInput( EndExtTextInputFlags 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; + + friend class GtkSalObjectWidgetClip; + + SalX11Screen m_nXScreen; + GtkWidget* m_pWindow; + GtkHeaderBar* m_pHeaderBar; + GtkGrid* m_pTopLevelGrid; + GtkEventBox* m_pEventBox; + GtkFixed* m_pFixedContainer; + GdkWindow* m_pForeignParent; + GdkNativeWindow m_aForeignParentWindow; + GdkWindow* m_pForeignTopLevel; + GdkNativeWindow m_aForeignTopLevelWindow; + SalFrameStyleFlags m_nStyle; + GtkSalFrame* m_pParent; + std::list< GtkSalFrame* > m_aChildren; + GdkWindowState m_nState; + SystemEnvData m_aSystemData; + std::unique_ptr m_pGraphics; + bool m_bGraphics; + ModKeyFlags m_nKeyModifiers; + GdkCursor *m_pCurrentCursor; + PointerStyle m_ePointerStyle; + ScreenSaverInhibitor m_ScreenSaverInhibitor; + bool m_bFullscreen; + bool m_bSpanMonitorsWhenFullscreen; + bool m_bDefaultPos; + bool m_bDefaultSize; + bool m_bTooltipBlocked; + OUString m_sWMClass; + + std::unique_ptr m_pIMHandler; + + Size m_aMaxSize; + Size m_aMinSize; + tools::Rectangle m_aRestorePosSize; + + OUString m_aTooltip; + tools::Rectangle m_aHelpArea; + tools::Rectangle m_aFloatRect; + FloatWinPopupFlags m_nFloatFlags; + bool m_bFloatPositioned; + long m_nWidthRequest; + long m_nHeightRequest; + cairo_region_t* m_pRegion; + GtkDropTarget* m_pDropTarget; + GtkDragSource* m_pDragSource; + bool m_bGeometryIsProvisional; + bool m_bIconSetWhileUnmapped; + + GtkSalMenu* m_pSalMenu; + +#if ENABLE_DBUS && ENABLE_GIO + private: + friend void ensure_dbus_setup(GdkWindow* gdkWindow, GtkSalFrame* pSalFrame); + friend void on_registrar_available (GDBusConnection*, const gchar*, const gchar*, gpointer); + friend void on_registrar_unavailable (GDBusConnection*, const gchar*, gpointer); +#endif + guint m_nWatcherId; + + void Init( SalFrame* pParent, SalFrameStyleFlags nStyle ); + void Init( SystemParentData* pSysData ); + void InitCommon(); + void InvalidateGraphics(); + + // signals + static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer ); + static void signalStyleUpdated(GtkWidget*, gpointer); + static gboolean signalDraw( GtkWidget*, cairo_t *cr, gpointer ); + static void signalRealize(GtkWidget*, gpointer frame); + static void sizeAllocated(GtkWidget*, GdkRectangle *pAllocation, gpointer frame); + static gboolean signalTooltipQuery(GtkWidget*, gint x, gint y, + gboolean keyboard_mode, GtkTooltip *tooltip, + gpointer frame); + static gboolean signalDragMotion(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + guint time, gpointer frame); + static gboolean signalDragDrop(GtkWidget* widget, GdkDragContext *context, gint x, gint y, + guint time, gpointer frame); + static void signalDragDropReceived(GtkWidget *widget, GdkDragContext *context, gint x, gint y, + GtkSelectionData *data, guint ttype, guint time, gpointer frame); + static void signalDragLeave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer frame); + + static gboolean signalDragFailed(GtkWidget *widget, GdkDragContext *context, GtkDragResult result, gpointer frame); + static void signalDragDelete(GtkWidget *widget, GdkDragContext *context, gpointer frame); + static void signalDragEnd(GtkWidget *widget, GdkDragContext *context, gpointer frame); + static void signalDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData *data, guint info, + guint time, gpointer frame); + + static void gestureSwipe(GtkGestureSwipe* gesture, gdouble velocity_x, gdouble velocity_y, gpointer frame); + static void gestureLongPress(GtkGestureLongPress* gesture, gdouble x, gdouble y, gpointer frame); + static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer ); + static void signalSetFocus( GtkWindow* pWindow, GtkWidget* pWidget, gpointer frame ); + 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 signalWindowState( GtkWidget*, GdkEvent*, gpointer ); + static gboolean signalScroll( GtkWidget*, GdkEvent*, gpointer ); + static gboolean signalCrossing( GtkWidget*, GdkEventCrossing*, gpointer ); + static gboolean signalVisibility( GtkWidget*, GdkEventVisibility*, gpointer ); + static void signalDestroy( GtkWidget*, gpointer ); + + void Center(); + void SetDefaultSize(); + + bool doKeyCallback( guint state, + guint keyval, + guint16 hardware_keycode, + guint8 group, + sal_Unicode aOrigCode, + bool bDown, + bool bSendRelease + ); + + static GdkNativeWindow findTopLevelSystemWindow( GdkNativeWindow aWindow ); + + static int m_nFloats; + + bool isFloatGrabWindow() const + { + return + (m_nStyle & SalFrameStyleFlags::FLOAT) && // only a float can be floatgrab + !(m_nStyle & SalFrameStyleFlags::TOOLTIP) && // tool tips are not + !(m_nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION); // toolbars are also not + } + + bool isChild( bool bPlug = true, bool bSysChild = true ) + { + SalFrameStyleFlags nMask = SalFrameStyleFlags::NONE; + if( bPlug ) + nMask |= SalFrameStyleFlags::PLUG; + if( bSysChild ) + nMask |= SalFrameStyleFlags::SYSTEMCHILD; + return bool(m_nStyle & nMask); + } + + //call gtk_window_resize + void window_resize(long nWidth, long nHeight); + //call gtk_widget_set_size_request + void widget_set_size_request(long nWidth, long nHeight); + + void resizeWindow( long nWidth, long nHeight ); + void moveWindow( long nX, long nY ); + + Size calcDefaultSize(); + + void setMinMaxSize(); + + void AllocateFrame(); + void TriggerPaintEvent(); + + void updateWMClass(); + + enum class SetType { RetainSize, Fullscreen, UnFullscreen }; + + void SetScreen( unsigned int nNewScreen, SetType eType, tools::Rectangle const *pSize = nullptr ); + + void SetIcon(const char* pIcon); + +public: + cairo_surface_t* m_pSurface; + basegfx::B2IVector m_aFrameSize; + DamageHandler m_aDamageHandler; + std::vector m_aPendingScrollEvents; + Idle m_aSmoothScrollIdle; + int m_nGrabLevel; + bool m_bSalObjectSetPosSize; + GtkSalFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ); + GtkSalFrame( SystemParentData* pSysData ); + + guint m_nMenuExportId; + guint m_nActionGroupExportId; + guint m_nHudAwarenessId; + std::vector m_aMouseSignalIds; + + void grabPointer(bool bGrab, bool bKeyboardAlso, bool bOwnerEvents); + + static GtkSalDisplay* getDisplay(); + static GdkDisplay* getGdkDisplay(); + GtkWidget* getWindow() const { return m_pWindow; } + GtkFixed* getFixedContainer() const { return m_pFixedContainer; } + GtkEventBox* getEventBox() const { return m_pEventBox; } + GtkWidget* getMouseEventWidget() const; + GtkGrid* getTopLevelGridWidget() const { return m_pTopLevelGrid; } + const SalX11Screen& getXScreenNumber() const { return m_nXScreen; } + int GetDisplayScreen() const { return maGeometry.nDisplayScreenNumber; } + void updateScreenNumber(); + + cairo_t* getCairoContext() const; + void damaged(sal_Int32 nExtentsLeft, sal_Int32 nExtentsTop, + sal_Int32 nExtentsRight, sal_Int32 nExtentsBottom) const; + + void registerDropTarget(GtkDropTarget* pDropTarget) + { + assert(!m_pDropTarget); + m_pDropTarget = pDropTarget; + } + + void deregisterDropTarget(GtkDropTarget const * pDropTarget) + { + assert(m_pDropTarget == pDropTarget); (void)pDropTarget; + m_pDropTarget = nullptr; + } + + void registerDragSource(GtkDragSource* pDragSource) + { + assert(!m_pDragSource); + m_pDragSource = pDragSource; + } + + void deregisterDragSource(GtkDragSource const * pDragSource) + { + assert(m_pDragSource == pDragSource); (void)pDragSource; + m_pDragSource = nullptr; + } + + void startDrag(gint nButton, gint nDragOriginX, gint nDragOriginY, + GdkDragAction sourceActions, GtkTargetList* pTargetList); + + void closePopup(); + + void addGrabLevel(); + void removeGrabLevel(); + + void nopaint_container_resize_children(GtkContainer*); + + void LaunchAsyncScroll(GdkEvent const * pEvent); + DECL_LINK(AsyncScroll, Timer *, void); + + virtual ~GtkSalFrame() override; + + // SalGraphics or NULL, but two Graphics for all SalFrames + // must be returned + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + // Event must be destroyed, when Frame is destroyed + // When Event is called, SalInstance::Yield() must be returned + virtual bool PostEvent(std::unique_ptr pData) override; + + virtual void SetTitle( const OUString& rTitle ) override; + virtual void SetIcon( sal_uInt16 nIcon ) override; + virtual void SetMenu( SalMenu *pSalMenu ) override; + SalMenu* GetMenu(); + virtual void DrawMenuBar() override; + void EnsureAppMenuWatch(); + + virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ) override; + // Before the window is visible, a resize event + // must be sent with the correct size + virtual void Show( bool bVisible, bool bNoActivate = false ) override; + // Set ClientSize and Center the Window to the desktop + // and send/post a resize message + virtual void SetMinClientSize( long nWidth, long nHeight ) override; + virtual void SetMaxClientSize( long nWidth, long nHeight ) override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) override; + virtual void GetClientSize( long& rWidth, long& rHeight ) override; + virtual void GetWorkArea( tools::Rectangle& rRect ) override; + virtual SalFrame* GetParent() const override; + virtual void SetWindowState( const SalFrameState* pState ) override; + virtual bool GetWindowState( SalFrameState* pState ) override; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) override; + // Enable/Disable ScreenSaver, SystemAgents, ... + virtual void StartPresentation( bool bStart ) override; + // Show Window over all other Windows + virtual void SetAlwaysOnTop( bool bOnTop ) override; + + // Window to top and grab focus + virtual void ToTop( SalFrameToTop nFlags ) override; + + // this function can call with the same + // pointer style + virtual void SetPointer( PointerStyle ePointerStyle ) override; + virtual void CaptureMouse( bool bMouse ) override; + virtual void GrabFocus() override; + virtual void SetPointerPos( long nX, long nY ) override; + + // flush output buffer + using SalFrame::Flush; + virtual void Flush() override; + // flush output buffer, wait till outstanding operations are done + + virtual void SetInputContext( SalInputContext* pContext ) override; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) override; + + virtual OUString GetKeyName( sal_uInt16 nKeyCode ) override; + virtual bool MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode ) override; + + // returns the input language used for the last key stroke + // may be LANGUAGE_DONTKNOW if not supported by the OS + virtual LanguageType GetInputLanguage() override; + + virtual void UpdateSettings( AllSettings& rSettings ) override; + + virtual void Beep() override; + + // returns system data (most prominent: window handle) + virtual const SystemEnvData* GetSystemData() const override; + + // get current modifier and button mask + virtual SalPointerState GetPointerState() override; + + virtual KeyIndicatorState GetIndicatorState() override; + + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) override; + + // set new parent window + virtual void SetParent( SalFrame* pNewParent ) override; + // 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 ) override; + + virtual void SetScreenNumber( unsigned int ) override; + virtual void SetApplicationID( const OUString &rWMClass ) override; + + // shaped system windows + // set clip region to none (-> rectangular windows, normal state) + virtual void ResetClipRegion() override; + // start setting the clipregion consisting of nRects rectangles + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + // add a rectangle to the clip region + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + // done setting up the clipregion + virtual void EndSetClipRegion() override; + + virtual void PositionByToolkit(const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override; + virtual void SetModal(bool bModal) override; + virtual bool GetModal() const override; + void HideTooltip(); + void BlockTooltip(); + void UnblockTooltip(); + virtual bool ShowTooltip(const OUString& rHelpText, const tools::Rectangle& rHelpArea) override; + virtual void* ShowPopover(const OUString& rHelpText, vcl::Window* pParent, const tools::Rectangle& rHelpArea, QuickHelpFlags nFlags) override; + virtual bool UpdatePopover(void* nId, const OUString& rHelpText, vcl::Window* pParent, const tools::Rectangle& rHelpArea) override; + virtual bool HidePopover(void* nId) override; + virtual weld::Window* GetFrameWeld() const override; + + static GtkSalFrame *getFromWindow( GtkWidget *pWindow ); + + sal_uIntPtr GetNativeWindowHandle(GtkWidget *pWidget); + virtual sal_uIntPtr GetNativeWindowHandle() override; + + //Call the usual SalFrame Callback, but catch uno exceptions and delegate + //to GtkSalData to rethrow them after the gsignal is processed when its safe + //to do so again in our own code after the g_main_context_iteration call + //which triggers the gsignals. + bool CallCallbackExc(SalEvent nEvent, const void* pEvent) const; + + + static void KeyCodeToGdkKey(const vcl::KeyCode& rKeyCode, + guint* pGdkKeyCode, GdkModifierType *pGdkModifiers); + + static guint32 GetLastInputEventTime(); + static void UpdateLastInputEventTime(guint32 nUserInputTime); + static sal_uInt16 GetMouseModCode(guint nState); + static sal_uInt16 GetKeyCode(guint nKeyVal); + static guint GetKeyValFor(GdkKeymap* pKeyMap, guint16 hardware_keycode, guint8 group); + static sal_uInt16 GetKeyModCode(guint nState); + static GdkEvent* makeFakeKeyPress(GtkWidget* pWidget); + static SalWheelMouseEvent GetWheelEvent(GdkEventScroll& rEvent); + static gboolean NativeWidgetHelpPressed(GtkAccelGroup*, GObject*, guint, + GdkModifierType, gpointer pFrame); + static OUString GetPreeditDetails(GtkIMContext* pIMContext, std::vector& rInputFlags, sal_Int32& rCursorPos, sal_uInt8& rCursorFlags); +}; + +#define OOO_TYPE_FIXED ooo_fixed_get_type() + +extern "C" { + +GType ooo_fixed_get_type(); +AtkObject* ooo_fixed_get_accessible(GtkWidget *obj); + +} // extern "C" + +#if !GTK_CHECK_VERSION(3, 20, 0) +enum GdkDragCancelReason +{ + GDK_DRAG_CANCEL_NO_TARGET, + GDK_DRAG_CANCEL_USER_CANCELLED, + GDK_DRAG_CANCEL_ERROR +}; +#endif + +#if !GTK_CHECK_VERSION(3, 22, 0) +enum GdkAnchorHints +{ + GDK_ANCHOR_FLIP_X = 1 << 0, + GDK_ANCHOR_FLIP_Y = 1 << 1, + GDK_ANCHOR_SLIDE_X = 1 << 2, + GDK_ANCHOR_SLIDE_Y = 1 << 3, + GDK_ANCHOR_RESIZE_X = 1 << 4, + GDK_ANCHOR_RESIZE_Y = 1 << 5, + GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y, + GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y, + GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y +}; +#endif + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKFRAME_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx new file mode 100644 index 000000000..430bab56d --- /dev/null +++ b/vcl/inc/unx/gtk/gtkgdi.hxx @@ -0,0 +1,399 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKGDI_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKGDI_HXX + +#include + +#include +#include "gtkbackend.hxx" +#include + +#include +#include + +#include +#include + +enum class GtkControlPart +{ + ToplevelWindow, + Button, + LinkButton, + CheckButton, + CheckButtonCheck, + RadioButton, + RadioButtonRadio, + Entry, + Combobox, + ComboboxBox, + ComboboxBoxEntry, + ComboboxBoxButton, + ComboboxBoxButtonBox, + ComboboxBoxButtonBoxArrow, + Listbox, + ListboxBox, + ListboxBoxButton, + ListboxBoxButtonBox, + ListboxBoxButtonBoxArrow, + SpinButton, + SpinButtonEntry, + SpinButtonUpButton, + SpinButtonDownButton, + ScrollbarVertical, + ScrollbarVerticalContents, + ScrollbarVerticalTrough, + ScrollbarVerticalSlider, + ScrollbarVerticalButton, + ScrollbarHorizontal, + ScrollbarHorizontalContents, + ScrollbarHorizontalTrough, + ScrollbarHorizontalSlider, + ScrollbarHorizontalButton, + ProgressBar, + ProgressBarTrough, + ProgressBarProgress, + Notebook, + NotebookHeader, + NotebookStack, + NotebookHeaderTabs, + NotebookHeaderTabsTab, + NotebookHeaderTabsTabLabel, + NotebookHeaderTabsTabActiveLabel, + NotebookHeaderTabsTabHoverLabel, + FrameBorder, + MenuBar, + MenuBarItem, + MenuWindow, + Menu, + MenuItem, + MenuItemLabel, + MenuItemArrow, + CheckMenuItem, + CheckMenuItemCheck, + RadioMenuItem, + RadioMenuItemRadio, + SeparatorMenuItem, + SeparatorMenuItemSeparator, +}; + +typedef void (*gtk_widget_path_iter_set_object_nameFunc)(GtkWidgetPath *, guint, const char*); + +class GtkSalGraphics : public SvpSalGraphics +{ + GtkSalFrame * const mpFrame; + +protected: + bool isNativeControlSupported(ControlType, ControlPart) override; + virtual bool drawNativeControl( ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const OUString& rCaption, + const Color& rBackgroundColor ) override; + virtual bool getNativeControlRegion( ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + const OUString& rCaption, + tools::Rectangle &rNativeBoundingRegion, + tools::Rectangle &rNativeContentRegion ) override; + bool updateSettings(AllSettings&) override; + void handleDamage(const tools::Rectangle&) override; + +public: + GtkSalGraphics( GtkSalFrame *pFrame, GtkWidget *pWindow ); + +#if ENABLE_CAIRO_CANVAS + + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override; + +#endif + + void WidgetQueueDraw() const; + + virtual void GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) override; + + virtual OUString getRenderBackendName() const override { return "gtk3svp"; } + + GtkStyleContext* createStyleContext(gtk_widget_path_iter_set_object_nameFunc set_object_name, GtkControlPart ePart); + GtkStyleContext* createNewContext(GtkControlPart ePart, gtk_widget_path_iter_set_object_nameFunc set_object_name); + GtkStyleContext* createOldContext(GtkControlPart ePart); + GtkStyleContext* makeContext(GtkWidgetPath *pPath, GtkStyleContext *pParent); +private: + GtkWidget *mpWindow; + static GtkStyleContext *mpWindowStyle; + static GtkStyleContext *mpButtonStyle; + static GtkStyleContext *mpLinkButtonStyle; + static GtkStyleContext *mpEntryStyle; + static GtkStyleContext *mpTextViewStyle; + static GtkStyleContext *mpVScrollbarStyle; + static GtkStyleContext *mpVScrollbarContentsStyle; + static GtkStyleContext *mpVScrollbarTroughStyle; + static GtkStyleContext *mpVScrollbarSliderStyle; + static GtkStyleContext *mpVScrollbarButtonStyle; + static GtkStyleContext *mpHScrollbarStyle; + static GtkStyleContext *mpHScrollbarContentsStyle; + static GtkStyleContext *mpHScrollbarTroughStyle; + static GtkStyleContext *mpHScrollbarSliderStyle; + static GtkStyleContext *mpHScrollbarButtonStyle; + static GtkStyleContext *mpToolbarStyle; + static GtkStyleContext *mpToolButtonStyle; + static GtkStyleContext *mpToolbarSeperatorStyle; + static GtkStyleContext *mpCheckButtonStyle; + static GtkStyleContext *mpCheckButtonCheckStyle; + static GtkStyleContext *mpRadioButtonStyle; + static GtkStyleContext *mpRadioButtonRadioStyle; + static GtkStyleContext *mpSpinStyle; + static GtkStyleContext *mpSpinEntryStyle; + static GtkStyleContext *mpSpinUpStyle; + static GtkStyleContext *mpSpinDownStyle; + static GtkStyleContext *mpComboboxStyle; + static GtkStyleContext *mpComboboxBoxStyle; + static GtkStyleContext *mpComboboxEntryStyle; + static GtkStyleContext *mpComboboxButtonStyle; + static GtkStyleContext *mpComboboxButtonBoxStyle; + static GtkStyleContext *mpComboboxButtonArrowStyle; + static GtkStyleContext *mpListboxStyle; + static GtkStyleContext *mpListboxBoxStyle; + static GtkStyleContext *mpListboxButtonStyle; + static GtkStyleContext *mpListboxButtonBoxStyle; + static GtkStyleContext *mpListboxButtonArrowStyle; + static GtkStyleContext *mpFrameInStyle; + static GtkStyleContext *mpFrameOutStyle; + static GtkStyleContext *mpFixedHoriLineStyle; + static GtkStyleContext *mpFixedVertLineStyle; + static GtkStyleContext *mpTreeHeaderButtonStyle; + static GtkStyleContext *mpProgressBarStyle; + static GtkStyleContext *mpProgressBarTroughStyle; + static GtkStyleContext *mpProgressBarProgressStyle; + static GtkStyleContext *mpNotebookStyle; + static GtkStyleContext *mpNotebookStackStyle; + static GtkStyleContext *mpNotebookHeaderStyle; + static GtkStyleContext *mpNotebookHeaderTabsStyle; + static GtkStyleContext *mpNotebookHeaderTabsTabStyle; + static GtkStyleContext *mpNotebookHeaderTabsTabLabelStyle; + static GtkStyleContext *mpNotebookHeaderTabsTabActiveLabelStyle; + static GtkStyleContext *mpNotebookHeaderTabsTabHoverLabelStyle; + static GtkStyleContext *mpMenuBarStyle; + static GtkStyleContext *mpMenuBarItemStyle; + static GtkStyleContext *mpMenuWindowStyle; + static GtkStyleContext *mpMenuStyle; + static GtkStyleContext *mpMenuItemStyle; + static GtkStyleContext *mpMenuItemLabelStyle; + static GtkStyleContext *mpMenuItemArrowStyle; + static GtkStyleContext *mpCheckMenuItemStyle; + static GtkStyleContext *mpCheckMenuItemCheckStyle; + static GtkStyleContext *mpRadioMenuItemStyle; + static GtkStyleContext *mpRadioMenuItemRadioStyle; + static GtkStyleContext *mpSeparatorMenuItemStyle; + static GtkStyleContext *mpSeparatorMenuItemSeparatorStyle; + + static tools::Rectangle NWGetScrollButtonRect( ControlPart nPart, tools::Rectangle aAreaRect ); + static tools::Rectangle NWGetSpinButtonRect( ControlPart nPart, tools::Rectangle aAreaRect); + static tools::Rectangle NWGetComboBoxButtonRect(ControlType nType, ControlPart nPart, tools::Rectangle aAreaRect); + + static void PaintScrollbar(GtkStyleContext *context, + cairo_t *cr, + const tools::Rectangle& rControlRectangle, + ControlPart nPart, + const ImplControlValue& aValue ); + void PaintOneSpinButton( GtkStyleContext *context, + cairo_t *cr, + ControlPart nPart, + tools::Rectangle aAreaRect, + ControlState nState ); + void PaintSpinButton(GtkStateFlags flags, + cairo_t *cr, + const tools::Rectangle& rControlRectangle, + ControlPart nPart, + const ImplControlValue& aValue); + static void PaintCombobox(GtkStateFlags flags, + cairo_t *cr, + const tools::Rectangle& rControlRectangle, + ControlType nType, + ControlPart nPart); + static void PaintCheckOrRadio(cairo_t *cr, GtkStyleContext *context, + const tools::Rectangle& rControlRectangle, + bool bIsCheck, bool bInMenu); + + static void PaintCheck(cairo_t *cr, GtkStyleContext *context, + const tools::Rectangle& rControlRectangle, bool bInMenu); + + static void PaintRadio(cairo_t *cr, GtkStyleContext *context, + const tools::Rectangle& rControlRectangle, bool bInMenu); + + + static bool style_loaded; +}; + +#else +#include + +class GdkX11Pixmap; +class GtkSalGraphics : public X11SalGraphics +{ + GtkWidget *m_pWindow; + vcl::Region m_aClipRegion; + +public: + GtkSalGraphics(GtkSalFrame *, GtkWidget *window, SalX11Screen nXScreen); + virtual ~GtkSalGraphics() override; + + GtkWidget* GetGtkWidget() const { return m_pWindow; } + GdkWindow* GetGdkWindow() const { return m_pWindow->window; } + GtkSalFrame* GetGtkFrame() const { return static_cast(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 bNeedTwoPasses; + +protected: + // native widget methods + bool isNativeControlSupported(ControlType, ControlPart) override; + virtual bool hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + const Point& aPos, bool& rIsInside ) override; + virtual bool drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const OUString& rCaption, const Color& rBackgroundColor ) override; + virtual bool getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& rCaption, + tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override; + bool updateSettings(AllSettings&) override; + +public: + //helper methods for frame's UpdateSettings + static void refreshFontconfig( GtkSettings *pSettings ); + static void signalSettingsNotify( GObject*, GParamSpec *pSpec, gpointer ); + + virtual bool setClipRegion( const vcl::Region& ) override; + virtual void ResetClipRegion() override; + + // 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& rPosAry, + SalGraphics* pSrcGraphics ) override; + + virtual OUString getRenderBackendName() const override { return "gtk3"; } + +protected: + + std::unique_ptr NWGetPixmapFromScreen( tools::Rectangle srcRect, int nBgColor = 0 ); + bool NWRenderPixmapToScreen( GdkX11Pixmap* pPixmap, GdkX11Pixmap* pMask, tools::Rectangle dstRect ); + + bool DoDrawNativeControl( GdkDrawable* pDrawable, + ControlType nType, + ControlPart nPart, + const tools::Rectangle& aCtrlRect, + const std::vector< tools::Rectangle >& aClip, + ControlState nState, + const ImplControlValue& aValue, + ControlCacheKey& rControlCacheKey); + + bool NWPaintGTKArrow( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKListHeader( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKFixedLine( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle ); + bool NWPaintGTKFrame( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + const ImplControlValue& aValue ); + bool NWPaintGTKWindowBackground( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList ); + bool NWPaintGTKButtonReal( GtkWidget* button, GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKButton( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKRadio( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKCheck( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKScrollbar( ControlPart nPart, + const tools::Rectangle& rControlRectangle, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKEditBox( GdkDrawable* gdkDrawable, ControlType nType, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKSpinBox(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + ControlState nState, const ImplControlValue& aValue, + ControlCacheKey& rControlCacheKey); + bool NWPaintGTKComboBox( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKTabItem( ControlType nType, + const tools::Rectangle& rControlRectangle, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKListBox( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + + bool NWPaintGTKToolbar( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKMenubar( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKPopupMenu( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList, + ControlState nState ); + bool NWPaintGTKTooltip( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + const std::vector< tools::Rectangle >& rClipList ); + bool NWPaintGTKProgress( + const tools::Rectangle& rControlRectangle, + const ImplControlValue& aValue ); + bool NWPaintGTKSlider( GdkDrawable* gdkDrawable, ControlPart nPart, + const tools::Rectangle& rControlRectangle, + ControlState nState, const ImplControlValue& aValue ); + bool NWPaintGTKListNode( GdkDrawable* gdkDrawable, + const tools::Rectangle& rControlRectangle, + ControlState nState, const ImplControlValue& aValue ); +}; + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKGDI_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx new file mode 100644 index 000000000..3402aa6e3 --- /dev/null +++ b/vcl/inc/unx/gtk/gtkinst.hxx @@ -0,0 +1,298 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKINST_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKINST_HXX + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vcl +{ +namespace unx +{ +class GtkPrintWrapper; +} +} + +vcl::Font pango_to_vcl(const PangoFontDescription* font, const css::lang::Locale& rLocale); + +class GenPspGraphics; +class GtkYieldMutex final : public SalYieldMutex +{ + thread_local static std::stack yieldCounts; + +public: + GtkYieldMutex() {} + void ThreadsEnter(); + void ThreadsLeave(); +}; + +class GtkSalFrame; + +struct VclToGtkHelper +{ + std::vector aInfoToFlavor; + std::vector FormatsToGtk(const css::uno::Sequence &rFormats); + void setSelectionData(const css::uno::Reference &rTrans, + GtkSelectionData *selection_data, guint info); +private: + GtkTargetEntry makeGtkTargetEntry(const css::datatransfer::DataFlavor& rFlavor); +}; + +class GtkTransferable : public cppu::WeakImplHelper +{ +protected: + std::map m_aMimeTypeToAtom; + + std::vector getTransferDataFlavorsAsVector(GdkAtom *targets, gint n_targets); + +public: + virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor& rFlavor) override = 0; + virtual std::vector getTransferDataFlavorsAsVector() = 0; + virtual css::uno::Sequence SAL_CALL getTransferDataFlavors() override; + virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) override; +}; + +class GtkDnDTransferable; + +class GtkDropTarget final : public cppu::WeakComponentImplHelper +{ + osl::Mutex m_aMutex; + GtkSalFrame* m_pFrame; + GtkDnDTransferable* m_pFormatConversionRequest; + bool m_bActive; + bool m_bInDrag; + sal_Int8 m_nDefaultActions; + std::vector> m_aListeners; +public: + GtkDropTarget(); + virtual ~GtkDropTarget() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArgs) override; + void deinitialize(); + + // XDropTarget + virtual void SAL_CALL addDropTargetListener(const css::uno::Reference&) override; + virtual void SAL_CALL removeDropTargetListener(const css::uno::Reference&) override; + virtual sal_Bool SAL_CALL isActive() override; + virtual void SAL_CALL setActive(sal_Bool active) override; + virtual sal_Int8 SAL_CALL getDefaultActions() override; + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override; + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee); + void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEvent& dtde); + void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde); + void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte); + + void SetFormatConversionRequest(GtkDnDTransferable *pRequest) + { + m_pFormatConversionRequest = pRequest; + } + + gboolean signalDragDrop(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time); + gboolean signalDragMotion(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, guint time); + void signalDragDropReceived(GtkWidget* pWidget, GdkDragContext* context, gint x, gint y, GtkSelectionData* data, guint ttype, guint time); + void signalDragLeave(GtkWidget* pWidget, GdkDragContext* context, guint time); +}; + +class GtkDragSource final : public cppu::WeakComponentImplHelper +{ + osl::Mutex m_aMutex; + GtkSalFrame* m_pFrame; + css::uno::Reference m_xListener; + css::uno::Reference m_xTrans; + VclToGtkHelper m_aConversionHelper; +public: + GtkDragSource() + : WeakComponentImplHelper(m_aMutex) + , m_pFrame(nullptr) + { + } + + void set_datatransfer(const css::uno::Reference& rTrans, + const css::uno::Reference& rListener); + + std::vector FormatsToGtk(const css::uno::Sequence &rFormats); + + void setActiveDragSource(); + + virtual ~GtkDragSource() override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported() override; + virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) override; + virtual void SAL_CALL startDrag( + const css::datatransfer::dnd::DragGestureEvent& trigger, sal_Int8 sourceActions, sal_Int32 cursor, sal_Int32 image, + const css::uno::Reference< css::datatransfer::XTransferable >& transferable, + const css::uno::Reference< css::datatransfer::dnd::XDragSourceListener >& listener) override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence& rArguments) override; + void deinitialize(); + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + void dragFailed(); + void dragDelete(); + void dragEnd(GdkDragContext* context); + void dragDataGet(GtkSelectionData *data, guint info); + + // For LibreOffice internal D&D we provide the Transferable without Gtk + // intermediaries as a shortcut, see tdf#100097 for how dbaccess depends on this + static GtkDragSource* g_ActiveDragSource; + css::uno::Reference const & GetTransferrable() const { return m_xTrans; } +}; + +class GtkSalTimer; +class GtkInstance final : public SvpSalInstance +{ +public: + GtkInstance( std::unique_ptr pMutex ); + virtual ~GtkInstance() override; + void EnsureInit(); + virtual void AfterAppInit() override; + + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ) override; + virtual SalSystem* CreateSalSystem() override; + virtual SalInfoPrinter* CreateInfoPrinter(SalPrinterQueueInfo* pPrinterQueueInfo, ImplJobSetup* pJobSetup) override; + virtual std::unique_ptr CreatePrinter( SalInfoPrinter* pInfoPrinter ) override; + virtual std::unique_ptr CreateMenu( bool, Menu* ) override; + virtual std::unique_ptr CreateMenuItem( const SalItemParams& ) override; + virtual SalTimer* CreateSalTimer() override; + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; + virtual std::unique_ptr + CreateVirtualDevice( SalGraphics*, + long &nDX, long &nDY, + DeviceFormat eFormat, + const SystemGraphicsData* = nullptr ) override; + virtual std::shared_ptr CreateSalBitmap() override; + + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput( VclInputFlags nType ) override; + // impossible to handle correctly, as "main thread" depends on the dispatch mutex + virtual bool IsMainThread() const override { return false; } + + virtual std::unique_ptr CreatePrintGraphics() override; + + virtual bool hasNativeFileSelection() const override { return true; } + + virtual css::uno::Reference< css::ui::dialogs::XFilePicker2 > + createFilePicker( const css::uno::Reference< css::uno::XComponentContext >& ) override; + virtual css::uno::Reference< css::ui::dialogs::XFolderPicker2 > + createFolderPicker( const css::uno::Reference< css::uno::XComponentContext >& ) override; + + virtual css::uno::Reference< css::uno::XInterface > CreateClipboard( const css::uno::Sequence< css::uno::Any >& i_rArguments ) override; + virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override; + virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override; + virtual OpenGLContext* CreateOpenGLContext() override; + virtual weld::Builder* CreateBuilder(weld::Widget* pParent, const OUString& rUIRoot, const OUString& rUIFile) override; + virtual weld::Builder* CreateInterimBuilder(vcl::Window* pParent, const OUString& rUIRoot, const OUString& rUIFile) override; + virtual weld::MessageDialog* CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage) override; + virtual weld::Window* GetFrameWeld(const css::uno::Reference& rWindow) override; + + virtual const cairo_font_options_t* GetCairoFontOptions() override; + const cairo_font_options_t* GetLastSeenCairoFontOptions() const; + void ResetLastSeenCairoFontOptions(const cairo_font_options_t* pOptions); + + void RemoveTimer (); + + std::shared_ptr const & getPrintWrapper() const; + + void* CreateGStreamerSink(const SystemChildWindow*) override; + +private: + GtkSalTimer *m_pTimer; + std::unordered_map< GdkAtom, css::uno::Reference > m_aClipboards; + bool IsTimerExpired(); + bool bNeedsInit; + cairo_font_options_t* m_pLastCairoFontOptions; + + mutable std::shared_ptr m_xPrintWrapper; +}; + +class SalGtkXWindow final : public weld::TransportAsXWindow +{ +private: + weld::Window* m_pWeldWidget; + GtkWidget* m_pWidget; +public: + + SalGtkXWindow(weld::Window* pWeldWidget, GtkWidget* pWidget) + : TransportAsXWindow(pWeldWidget) + , m_pWeldWidget(pWeldWidget) + , m_pWidget(pWidget) + { + } + + virtual void clear() override + { + m_pWeldWidget = nullptr; + m_pWidget = nullptr; + TransportAsXWindow::clear(); + } + + GtkWidget* getGtkWidget() const + { + return m_pWidget; + } + + weld::Window* getFrameWeld() const + { + return m_pWeldWidget; + } +}; + +GdkPixbuf* load_icon_by_name(const OUString& rIconName); + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKINST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkobject.hxx b/vcl/inc/unx/gtk/gtkobject.hxx new file mode 100644 index 000000000..d1a5226cd --- /dev/null +++ b/vcl/inc/unx/gtk/gtkobject.hxx @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKOBJECT_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKOBJECT_HXX + +#include +#include +#include +#include + +class GtkSalObjectBase : public SalObject +{ +protected: + SystemEnvData m_aSystemData; + GtkWidget* m_pSocket; + GtkSalFrame* m_pParent; + cairo_region_t* m_pRegion; + + void Init(); + +public: + GtkSalObjectBase(GtkSalFrame* pParent); + virtual ~GtkSalObjectBase() override; + + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + + virtual void SetForwardKey( bool bEnable ) override; + + virtual const SystemEnvData* GetSystemData() const override; + + virtual Size GetOptimalSize() const override; + +private: + // signals + static gboolean signalButton( GtkWidget*, GdkEventButton*, gpointer ); + static gboolean signalFocus( GtkWidget*, GdkEventFocus*, gpointer ); +}; + +// this attempts to clip the hosted native window using gdk_window_shape_combine_region +class GtkSalObject final : public GtkSalObjectBase +{ + // signals + static void signalDestroy( GtkWidget*, gpointer ); + +public: + GtkSalObject(GtkSalFrame* pParent, bool bShow); + virtual ~GtkSalObject() override; + + // override all pure virtual methods + virtual void ResetClipRegion() override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + virtual void Reparent(SalFrame* pFrame) override; +}; + +// this attempts to clip the hosted native GtkWidget by using a GtkScrolledWindow as a viewport +// only a rectangular area is going to work +class GtkSalObjectWidgetClip final : public GtkSalObjectBase +{ + tools::Rectangle m_aRect; + tools::Rectangle m_aClipRect; + GtkWidget* m_pScrolledWindow; + + // signals + static gboolean signalScroll( GtkWidget*, GdkEvent*, gpointer ); + static void signalDestroy( GtkWidget*, gpointer ); + + bool signal_scroll(GtkWidget* pScrolledWindow, GdkEvent* pEvent); + + void ApplyClipRegion(); +public: + GtkSalObjectWidgetClip(GtkSalFrame* pParent, bool bShow); + virtual ~GtkSalObjectWidgetClip() override; + + // override all pure virtual methods + virtual void ResetClipRegion() override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + virtual void Reparent(SalFrame* pFrame) override; +}; + + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKOBJECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkprintwrapper.hxx b/vcl/inc/unx/gtk/gtkprintwrapper.hxx new file mode 100644 index 000000000..589c800d7 --- /dev/null +++ b/vcl/inc/unx/gtk/gtkprintwrapper.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_GTK_INC_GTKPRINTWRAPPER_HXX +#define INCLUDED_VCL_UNX_GTK_INC_GTKPRINTWRAPPER_HXX + +#include + +#include + +#include +#include + +namespace vcl +{ +namespace unx +{ + +class GtkPrintWrapper +{ +private: + GtkPrintWrapper(const GtkPrintWrapper&) = delete; + GtkPrintWrapper& operator=(const GtkPrintWrapper&) = delete; +public: + GtkPrintWrapper(); + ~GtkPrintWrapper(); + + bool supportsPrinting() const; + bool supportsPrintSelection() const; + + // general printing support, since 2.10.0 + GtkPageSetup* page_setup_new() const; + + GtkPrintJob* print_job_new(const gchar* title, GtkPrinter* printer, GtkPrintSettings* settings, GtkPageSetup* page_setup) const; + void print_job_send(GtkPrintJob* job, GtkPrintJobCompleteFunc callback, gpointer user_data, GDestroyNotify dnotify) const; + gboolean print_job_set_source_file(GtkPrintJob* job, const gchar* filename, GError** error) const; + + const gchar* print_settings_get(GtkPrintSettings* settings, const gchar* key) const; + gboolean print_settings_get_collate(GtkPrintSettings* settings) const; + void print_settings_set_collate(GtkPrintSettings* settings, gboolean collate) const; + gint print_settings_get_n_copies(GtkPrintSettings* settings) const; + void print_settings_set_n_copies(GtkPrintSettings* settings, gint num_copies) const; + GtkPageRange* print_settings_get_page_ranges(GtkPrintSettings* settings, gint* num_ranges) const; + void print_settings_set_print_pages(GtkPrintSettings* settings, GtkPrintPages pages) const; + + GtkWidget* print_unix_dialog_new() const; + void print_unix_dialog_add_custom_tab(GtkPrintUnixDialog* dialog, GtkWidget* child, GtkWidget* tab_label) const; + GtkPrinter* print_unix_dialog_get_selected_printer(GtkPrintUnixDialog* dialog) const; + void print_unix_dialog_set_manual_capabilities(GtkPrintUnixDialog* dialog, GtkPrintCapabilities capabilities) const; + GtkPrintSettings* print_unix_dialog_get_settings(GtkPrintUnixDialog* dialog) const; + void print_unix_dialog_set_settings(GtkPrintUnixDialog* dialog, GtkPrintSettings* settings) const; + + // print selection support, since 2.17.4 + void print_unix_dialog_set_support_selection(GtkPrintUnixDialog* dialog, gboolean support_selection) const; + void print_unix_dialog_set_has_selection(GtkPrintUnixDialog* dialog, gboolean has_selection) const; +}; + +} +} + +#endif // INCLUDED_VCL_UNX_GTK_INC_GTKPRINTWRAPPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkprn.hxx b/vcl/inc/unx/gtk/gtkprn.hxx new file mode 100644 index 000000000..aa24f0e4d --- /dev/null +++ b/vcl/inc/unx/gtk/gtkprn.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKPRN_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKPRN_HXX + +#include + +#include + +struct GtkSalPrinter_Impl; + +class GtkSalPrinter final : public PspSalPrinter +{ +public: + GtkSalPrinter(SalInfoPrinter* i_pInfoPrinter); + + ~GtkSalPrinter() override; + + using PspSalPrinter::StartJob; + virtual bool StartJob( + const OUString* i_pFileName, const OUString& i_rJobName, + const OUString& i_rAppName, ImplJobSetup* io_pSetupData, + vcl::PrinterController& io_rController) override; + virtual bool EndJob() override; + +private: + bool impl_doJob( + const OUString* i_pFileName, const OUString& i_rJobName, + const OUString& i_rAppName, ImplJobSetup* io_pSetupData, + bool i_bCollate, vcl::PrinterController& io_rController); + +private: + std::unique_ptr m_xImpl; +}; + +class GtkSalInfoPrinter final : public PspSalInfoPrinter +{ +public: + sal_uInt32 GetCapabilities(const ImplJobSetup* i_pSetupData, PrinterCapType i_nType) override; +}; + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKPRN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx new file mode 100644 index 000000000..4bac1fe53 --- /dev/null +++ b/vcl/inc/unx/gtk/gtksalmenu.hxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKSALMENU_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKSALMENU_HXX + +#include +#include + +#include +#if ENABLE_GIO +#include +#endif + +#include +#include +#include +#include + +#include +#include + +class MenuItemList; +class GtkSalMenuItem; + +class GtkSalMenu : public SalMenu +{ +private: + std::vector< GtkSalMenuItem* > maItems; + Idle maUpdateMenuBarIdle; + + bool mbInActivateCallback; + bool mbMenuBar; + bool mbNeedsUpdate; + bool mbReturnFocusToDocument; + bool mbAddedGrab; + /// Even setting null icon on a menuitem can be expensive, so cache state to avoid that call + bool mbHasNullItemIcon = true; + GtkWidget* mpMenuBarContainerWidget; + std::unique_ptr mxPersonaImage; + BitmapEx maPersonaBitmap; + GtkWidget* mpMenuAllowShrinkWidget; + GtkWidget* mpMenuBarWidget; + GtkCssProvider* mpMenuBarContainerProvider; + GtkCssProvider* mpMenuBarProvider; + GtkWidget* mpCloseButton; + VclPtr mpVCLMenu; + GtkSalMenu* mpParentSalMenu; + GtkSalFrame* mpFrame; + + // GMenuModel and GActionGroup attributes + GMenuModel* mpMenuModel; + GActionGroup* mpActionGroup; + + void ImplUpdate(bool bRecurse, bool bRemoveDisabledEntries); + void ActivateAllSubmenus(Menu* pMenuBar); + + DECL_LINK(MenuBarHierarchyChangeHandler, Timer*, void); + +public: + GtkSalMenu( bool bMenuBar ); + virtual ~GtkSalMenu() override; + + virtual bool VisibleMenuBar() override; // 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 ) override; + virtual void RemoveItem( unsigned nPos ) override; + virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) override; + virtual void SetFrame( const SalFrame* pFrame ) override; + const GtkSalFrame* GetFrame() const; + virtual void CheckItem( unsigned nPos, bool bCheck ) override; + virtual void EnableItem( unsigned nPos, bool bEnable ) override; + virtual void ShowItem( unsigned nPos, bool bShow ) override; + virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText ) override; + virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage) override; + virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) override; + virtual void GetSystemMenuData( SystemMenuData* pData ) override; + + void SetMenu( Menu* pMenu ) { mpVCLMenu = pMenu; } + Menu* GetMenu() { return mpVCLMenu; } + void SetMenuModel(GMenuModel* pMenuModel); + unsigned GetItemCount() const { return maItems.size(); } + GtkSalMenuItem* GetItemAtPos( unsigned nPos ) { return maItems[ nPos ]; } + void SetActionGroup( GActionGroup* pActionGroup ) { mpActionGroup = pActionGroup; } + bool IsItemVisible( unsigned nPos ); + + void NativeSetItemText( unsigned nSection, unsigned nItemPos, const OUString& rText ); + void NativeSetItemIcon( unsigned nSection, unsigned nItemPos, const Image& rImage ); + bool NativeSetItemCommand( unsigned nSection, + unsigned nItemPos, + sal_uInt16 nId, + const gchar* aCommand, + MenuItemBits nBits, + bool bChecked, + bool bIsSubmenu ); + void NativeSetEnableItem( gchar const * aCommand, gboolean bEnable ); + void NativeCheckItem( unsigned nSection, unsigned nItemPos, MenuItemBits bits, gboolean bCheck ); + void NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ); + + static void DispatchCommand(const gchar* pMenuCommand); + static void Activate(const gchar* pMenuCommand); + static void Deactivate(const gchar* pMenuCommand); + void EnableUnity(bool bEnable); + virtual void ShowMenuBar( bool bVisible ) override; + bool PrepUpdate(); + virtual void Update() override; // Update this menu only. + // Update full menu hierarchy from this menu. + void UpdateFull () { ActivateAllSubmenus(mpVCLMenu); Update(); } + // Clear ActionGroup and MenuModel from full menu hierarchy + void ClearActionGroupAndMenuModel(); + GtkSalMenu* GetTopLevel(); + void SetNeedsUpdate(); + + GtkWidget* GetMenuBarContainerWidget() const { return mpMenuBarContainerWidget; } + + void CreateMenuBarWidget(); + void DestroyMenuBarWidget(); + gboolean SignalKey(GdkEventKey const * pEvent); + void ReturnFocus(); + + virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) override; + virtual void ShowCloseButton(bool bShow) override; + virtual bool CanGetFocus() const override; + virtual bool TakeFocus() override; + virtual int GetMenuBarHeight() const override; + virtual void ApplyPersona() override; +}; + +class GtkSalMenuItem : public SalMenuItem +{ +public: + GtkSalMenuItem( const SalItemParams* ); + virtual ~GtkSalMenuItem() override; + + GtkSalMenu* mpParentMenu; // The menu into which this menu item is inserted + GtkSalMenu* mpSubMenu; // Submenu of this item (if defined) + MenuItemType mnType; // Item type + sal_uInt16 mnId; // Item ID + bool mbVisible; // Item visibility. +}; + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKSALMENU_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtksys.hxx b/vcl/inc/unx/gtk/gtksys.hxx new file mode 100644 index 000000000..8775f5af0 --- /dev/null +++ b/vcl/inc/unx/gtk/gtksys.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef INCLUDED_VCL_INC_UNX_GTK_GTKSYS_HXX +#define INCLUDED_VCL_INC_UNX_GTK_GTKSYS_HXX + +#include +#include +#include +#include + +class GtkSalSystem final : public SalGenericSystem +{ + typedef std::deque > ScreenMonitors_t; + + GdkDisplay *mpDisplay; + // Number of monitors for every active screen. + ScreenMonitors_t maScreenMonitors; +public: + GtkSalSystem(); + virtual ~GtkSalSystem() override; + static GtkSalSystem *GetSingleton(); + + virtual bool IsUnifiedDisplay() override; + virtual unsigned int GetDisplayScreenCount() override; + virtual unsigned int GetDisplayBuiltInScreen() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel (unsigned int nScreen) override; + virtual int ShowNativeDialog (const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons) override; + SalX11Screen GetDisplayDefaultXScreen() + { return getXScreenFromDisplayScreen( GetDisplayBuiltInScreen() ); } + SalX11Screen getXScreenFromDisplayScreen(unsigned int nDisplayScreen); + void countScreenMonitors(); + // We have a 'screen' number that is combined from screen-idx + monitor-idx + int getScreenIdxFromPtr (GdkScreen *pScreen); + int getScreenMonitorIdx (GdkScreen *pScreen, int nX, int nY); + GdkScreen *getScreenMonitorFromIdx (int nIdx, gint &nMonitor); +}; + +#endif // INCLUDED_VCL_INC_UNX_GTK_GTKSYS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/hudawareness.h b/vcl/inc/unx/gtk/hudawareness.h new file mode 100644 index 000000000..eb80e12fe --- /dev/null +++ b/vcl/inc/unx/gtk/hudawareness.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_GTK_HUDAWARENESS_H +#define INCLUDED_VCL_INC_UNX_GTK_HUDAWARENESS_H + +#include + +G_BEGIN_DECLS + +typedef void (* HudAwarenessCallback) (gboolean hud_active, + gpointer user_data); + +guint hud_awareness_register (GDBusConnection *connection, + const gchar *object_path, + HudAwarenessCallback callback, + gpointer user_data, + GDestroyNotify notify, + GError **error); + +void hud_awareness_unregister (GDBusConnection *connection, + guint awareness_id); + +G_END_DECLS + +#endif // INCLUDED_VCL_INC_UNX_GTK_HUDAWARENESS_H diff --git a/vcl/inc/unx/helper.hxx b/vcl/inc/unx/helper.hxx new file mode 100644 index 000000000..ac018b374 --- /dev/null +++ b/vcl/inc/unx/helper.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_HELPER_HXX +#define INCLUDED_VCL_INC_UNX_HELPER_HXX + +#include + +#include + + +// forwards +namespace osl { class File; } + +namespace psp +{ + +void getPrinterPathList( std::vector< OUString >& rPathList, const char* pSubDir ); + +OUString const & getFontPath(); + +// normalized path (equivalent to realpath) +void normPath( OString& rPath ); + +// splits rOrgPath into dirname and basename +// rOrgPath will be subject to normPath +void splitPath( OString& rOrgPath, OString& rDir, OString& rBase ); + +enum class whichOfficePath { InstallationRootPath, UserPath, ConfigPath }; + +OUString getOfficePath( whichOfficePath ePath ); + +} // namespace + + +#endif // INCLUDED_VCL_INC_UNX_HELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/i18n_cb.hxx b/vcl/inc/unx/i18n_cb.hxx new file mode 100644 index 000000000..d6a505e0d --- /dev/null +++ b/vcl/inc/unx/i18n_cb.hxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_INC_UNX_I18N_CB_HXX +#define INCLUDED_VCL_INC_UNX_I18N_CB_HXX + +#include + +#include +#include + +extern "C" { + +// xim callbacks +void PreeditDoneCallback ( XIC ic, XPointer client_data, XPointer call_data); +int PreeditStartCallback( 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); + +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); + +// 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); + +} /* extern "C" */ + +struct preedit_text_t +{ + sal_Unicode *pUnicodeBuffer; + XIMFeedback *pCharStyle; + unsigned int nLength; + unsigned int nSize; + preedit_text_t() + : pUnicodeBuffer(nullptr) + , pCharStyle(nullptr) + , nLength(0) + , nSize(0) + { + } +}; + +class SalFrame; + +enum class PreeditStatus { + DontKnow = 0, + Active, + ActivationRequired, + StartPending +}; + +struct preedit_data_t +{ + SalFrame* pFrame; + PreeditStatus eState; + preedit_text_t aText; + SalExtTextInputEvent aInputEv; + std::vector< ExtTextInputAttr > aInputFlags; + preedit_data_t() + : pFrame(nullptr) + , eState(PreeditStatus::DontKnow) + { + } +}; + +#endif // INCLUDED_VCL_INC_UNX_I18N_CB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/i18n_ic.hxx b/vcl/inc/unx/i18n_ic.hxx new file mode 100644 index 000000000..c9302c5eb --- /dev/null +++ b/vcl/inc/unx/i18n_ic.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_I18N_IC_HXX +#define INCLUDED_VCL_INC_UNX_I18N_IC_HXX + +#include "i18n_cb.hxx" + +enum class EndExtTextInputFlags; + +class SalI18N_InputContext +{ + +private: + + Bool mbUseable; // system supports current locale ? + XIC maContext; + + 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 const *pIMStyles ); + static unsigned int GetWeightingOfIMStyle( XIMStyle n_style ); + bool IsSupportedIMStyle( XIMStyle n_style ) const; + +public: + + Bool UseContext() { return mbUseable; } + bool IsPreeditMode() const { return maClientData.eState == PreeditStatus::Active; } + XIC GetContext() { return maContext; } + + void ExtendEventMask( ::Window aFocusWindow ); + void SetICFocus( SalFrame* pFocusFrame ); + void UnsetICFocus(); + void HandleDestroyIM(); + + void EndExtTextInput(); + void CommitKeyEvent( sal_Unicode const * pText, std::size_t nLength ); + int UpdateSpotLocation(); + + void Map( SalFrame *pFrame ); + void Unmap(); + + SalI18N_InputContext( SalFrame *aFrame ); + ~SalI18N_InputContext(); +}; + +#endif // INCLUDED_VCL_INC_UNX_I18N_IC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/i18n_im.hxx b/vcl/inc/unx/i18n_im.hxx new file mode 100644 index 000000000..2539ab2da --- /dev/null +++ b/vcl/inc/unx/i18n_im.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_I18N_IM_HXX +#define INCLUDED_VCL_INC_UNX_I18N_IM_HXX + +#include + +#include + +#define bUseInputMethodDefault True + +class SalI18N_InputMethod +{ + bool mbUseable; // system supports locale as well as status + // and preedit style ? + XIM maMethod; + XIMCallback maDestroyCallback; + XIMStyles *mpStyles; + +public: + + Bool PosixLocale(); + bool UseMethod() { return mbUseable; } + XIM GetMethod() { return maMethod; } + void HandleDestroyIM(); + void CreateMethod( Display *pDisplay ); + XIMStyles *GetSupportedStyles() { return mpStyles; } + void SetLocale(); + bool FilterEvent( XEvent *pEvent, ::Window window ); + + SalI18N_InputMethod(); + ~SalI18N_InputMethod(); +}; + +#endif // INCLUDED_VCL_INC_UNX_I18N_IM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/i18n_keysym.hxx b/vcl/inc/unx/i18n_keysym.hxx new file mode 100644 index 000000000..318908739 --- /dev/null +++ b/vcl/inc/unx/i18n_keysym.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_I18N_KEYSYM_HXX +#define INCLUDED_VCL_INC_UNX_I18N_KEYSYM_HXX + +#include + +#include + +/* + 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 // INCLUDED_VCL_INC_UNX_I18N_KEYSYM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/i18n_xkb.hxx b/vcl/inc/unx/i18n_xkb.hxx new file mode 100644 index 000000000..473251b48 --- /dev/null +++ b/vcl/inc/unx/i18n_xkb.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_I18N_XKB_HXX +#define INCLUDED_VCL_INC_UNX_I18N_XKB_HXX + +#include + +#include + +class SalI18N_KeyboardExtension +{ +private: + + bool mbUseExtension; + int mnEventBase; + +public: + + SalI18N_KeyboardExtension( Display *pDisplay ); + + inline bool UseExtension() const ; // server and client support the + // extension + inline void UseExtension( bool bState );// used to disable the Extension + + void Dispatch( XEvent *pEvent ); // keep track of group changes + + inline int GetEventBase() const ; +}; + +inline bool +SalI18N_KeyboardExtension::UseExtension() const +{ + return mbUseExtension; +} + +inline void +SalI18N_KeyboardExtension::UseExtension( bool bState ) +{ + mbUseExtension = mbUseExtension && bState; +} + +inline int +SalI18N_KeyboardExtension::GetEventBase() const +{ + return mnEventBase; +} + +#endif // INCLUDED_VCL_INC_UNX_I18N_XKB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/nativewindowhandleprovider.hxx b/vcl/inc/unx/nativewindowhandleprovider.hxx new file mode 100644 index 000000000..1d85cb4cf --- /dev/null +++ b/vcl/inc/unx/nativewindowhandleprovider.hxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_NATIVEWINDOWHANDLEPROVIDER +#define INCLUDED_VCL_UNX_NATIVEWINDOWHANDLEPROVIDER + +#include + +class VCL_PLUGIN_PUBLIC NativeWindowHandleProvider +{ +public: + virtual ~NativeWindowHandleProvider(); + + virtual sal_uIntPtr GetNativeWindowHandle() = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/printergfx.hxx b/vcl/inc/unx/printergfx.hxx new file mode 100644 index 000000000..fcb8a9241 --- /dev/null +++ b/vcl/inc/unx/printergfx.hxx @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_PRINTERGFX_HXX +#define INCLUDED_VCL_INC_GENERIC_PRINTERGFX_HXX + +#include +#include +#include +#include + +#include + +#include +#include + +enum class PolyFlags : sal_uInt8; + +namespace psp { + +struct 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() + : mnRed(0) + , mnGreen(0) + , mnBlue(0) + , 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) + {} + + bool Is () const + { return meColorspace != eInvalid; } + + sal_uInt16 GetRed () const + { return mnRed; } + sal_uInt16 GetGreen () const + { return mnGreen; } + sal_uInt16 GetBlue () const + { return mnBlue; } + bool operator== (const PrinterColor& aColor) const + { + return aColor.Is() && Is() + && mnRed == aColor.mnRed + && mnGreen == aColor.mnGreen + && mnBlue == aColor.mnBlue; + } + bool operator!= (const PrinterColor& aColor) const + { return ! (aColor==*this); } + + PrinterColor& operator= (sal_uInt32 nRGB) + { + meColorspace = eRGB; + mnBlue = (nRGB & 0x000000ff); + mnGreen = (nRGB & 0x0000ff00) >> 8; + mnRed = (nRGB & 0x00ff0000) >> 16; + + return *this; + } +}; + +class GlyphSet; +class PrinterJob; +class PrintFontManager; +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 GetDepth () const = 0; +}; + +enum class ImageType { + TrueColorImage, + MonochromeImage, + PaletteImage, + GrayScaleImage +}; + +/* + * printer raster operations + */ + +struct GraphicsStatus +{ + OString maFont; + rtl_TextEncoding maEncoding; + bool mbArtItalic; + bool mbArtBold; + sal_Int32 mnTextHeight; + sal_Int32 mnTextWidth; + PrinterColor maColor; + double mfLineWidth; + + GraphicsStatus(); +}; + +class PrinterGfx +{ +private: + + /* common settings */ + + double mfScaleX; + double mfScaleY; + + sal_uInt32 mnDpi; + sal_uInt16 mnDepth; + + sal_uInt16 mnPSLevel; + bool mbColor; + bool mbUploadPS42Fonts; + + osl::File* mpPageBody; + + /* 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::vector< GlyphSet > maPS3Font; + + sal_Int32 mnFontID; + sal_Int32 mnTextAngle; + bool mbTextVertical; + PrintFontManager& mrFontMgr; + + /* bitmap drawing implementation */ + + void DrawPS1GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea); + void writePS2ImageHeader (const tools::Rectangle& rArea, psp::ImageType nType); + void writePS2Colorspace (const PrinterBmp& rBitmap, psp::ImageType nType); + void DrawPS2GrayImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea); + void DrawPS2PaletteImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea); + void DrawPS2TrueColorImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea); + void DrawPS2MonoImage (const PrinterBmp& rBitmap, const tools::Rectangle& rArea); + + /* clip region */ + + std::list< tools::Rectangle > maClipRegion; + bool JoinVerticalClipRectangles( std::list< tools::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(); } + +public: + /* graphics status update */ + void PSSetColor (); + void PSSetLineWidth (); + void PSSetFont (); + + /* graphics status functions */ + void PSSetColor (const PrinterColor& rColor) + { maVirtualStatus.maColor = rColor; } + + void PSSetFont (const OString& rName, + rtl_TextEncoding nEncoding) + { 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 PSScale (double fScaleX, double fScaleY); + void PSLineTo(const Point& rPoint ); + void PSPointOp (const Point& rPoint, const char* pOperator); + void PSHexString (const unsigned char* pString, sal_Int16 nLen); + void PSShowGlyph (const unsigned char nGlyphId); + + void OnEndJob (); + void writeResources( osl::File* pFile, std::vector< OString >& rSuppliedFonts ); + PrintFontManager& GetFontMgr () { return mrFontMgr; } + + void drawGlyph(const Point& rPoint, + sal_GlyphId aGlyphId); +public: + PrinterGfx(); + ~PrinterGfx(); + void Init (PrinterJob &rPrinterSpec); + void Init (const JobData& rData); + void Clear(); + + // query depth + sal_uInt16 GetBitCount () const { return mnDepth;} + + // clip region + void ResetClipRegion (); + void BeginSetClipRegion(); + void 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 tools::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 PolyFlags* pFlgAry ); + void DrawPolygonBezier (sal_uInt32 nPoints, + const Point* pPath, + const PolyFlags* pFlgAry); + void DrawPolyPolygonBezier (sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const Point* const* pPtAry, + const PolyFlags* const* pFlgAry); + + // eps + bool DrawEPS ( const tools::Rectangle& rBoundingBox, void* pPtr, sal_uInt32 nSize); + + // image drawing + void DrawBitmap (const tools::Rectangle& rDest, const tools::Rectangle& rSrc, + const PrinterBmp& rBitmap); + + // font and text handling + void SetFont ( + sal_Int32 nFontID, + sal_Int32 nPointHeight, + sal_Int32 nPointWidth, + sal_Int32 nAngle, + bool bVertical, + bool bArtItalic, + bool bArtBold + ); + 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 SetTextColor (PrinterColor const & rTextColor) + { maTextColor = rTextColor; } + + void DrawGlyph(const Point& rPoint, + const GlyphItem& rGlyph); + +}; + +} /* namespace psp */ + +#endif // INCLUDED_VCL_INC_GENERIC_PRINTERGFX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/printerjob.hxx b/vcl/inc/unx/printerjob.hxx new file mode 100644 index 000000000..33f92abc7 --- /dev/null +++ b/vcl/inc/unx/printerjob.hxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_GENERIC_PRINTERJOB_HXX +#define INCLUDED_VCL_INC_GENERIC_PRINTERJOB_HXX + +#include +#include + +#include + +namespace psp { + +class PrinterGfx; + +class PrinterJob +{ +private: + OUString maSpoolDirName; + OUString maFileName; // empty: spool to command, else spool to named file + OUString maJobTitle; + int mnFileMode; + + std::unique_ptr mpJobHeader; + std::unique_ptr mpJobTrailer; + + std::vector< std::unique_ptr > maPageVector; + std::vector< std::unique_ptr > maHeaderVector; + + 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; + + bool m_bQuickJob; + +private: + std::unique_ptr CreateSpoolFile (const OUString& rName, + const 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 ); + static void writeJobPatch( osl::File* File, const JobData& ); + static void 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 = nullptr) const; + bool IsColorPrinter () const; + + osl::File* GetCurrentPageBody (); + + const 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 nonexistent + * files use open, for existent 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 EndJob() has returned + * bIsQuickJob: the job was started as "direct print" meaning + * the quick command for spooling should be used instead + * of the normal command + */ + bool StartJob (const OUString& rFileName, + int nMode, + const OUString& rJobName, + const OUString& rAppName, + const JobData& rSetupData, + PrinterGfx* pGraphics, + bool bIsQuickJob + ); + bool EndJob (); + + void StartPage (const JobData& rJobSetup); + void EndPage (); +}; + +} // namespace psp + +#endif // INCLUDED_VCL_INC_GENERIC_PRINTERJOB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salbmp.h b/vcl/inc/unx/salbmp.h new file mode 100644 index 000000000..fc8450129 --- /dev/null +++ b/vcl/inc/unx/salbmp.h @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALBMP_H +#define INCLUDED_VCL_INC_UNX_SALBMP_H + +#include + +#include +#include +#include +#include + +struct BitmapBuffer; +class BitmapPalette; +class SalGraphics; +class ImplSalDDB; +class ImplSalBitmapCache; + + +class X11SalBitmap final : public SalBitmap +{ +private: + + static std::unique_ptr + ImplCreateDIB( + const Size& rSize, + sal_uInt16 nBitCount, + const BitmapPalette& rPal + ); + + static std::unique_ptr + ImplCreateDIB( + Drawable aDrawable, + SalX11Screen nXScreen, + long nDrawableDepth, + long nX, + long nY, + long nWidth, + long nHeight, + bool bGrey + ); + +public: + + static ImplSalBitmapCache* mpCache; + static unsigned int mnCacheInstCount; + + static void ImplCreateCache(); + static void ImplDestroyCache(); + void ImplRemovedFromCache(); + +private: + + std::unique_ptr mpDIB; + mutable std::unique_ptr mpDDB; + bool mbGrey; + +public: + + bool ImplCreateFromDrawable( + Drawable aDrawable, + SalX11Screen nXScreen, + long nDrawableDepth, + long nX, + long nY, + long nWidth, + long nHeight + ); + + XImage* ImplCreateXImage( + SalDisplay const * pSalDisp, + SalX11Screen nXScreen, + long nDepth, + const SalTwoRect& rTwoRect + ) const; + + ImplSalDDB* ImplGetDDB( + Drawable, + SalX11Screen nXScreen, + long nDrawableDepth, + const SalTwoRect& + ) const; + + void ImplDraw( + Drawable aDrawable, + SalX11Screen nXScreen, + long nDrawableDepth, + const SalTwoRect& rTwoRect, + const GC& rGC + ) const; + +public: + + X11SalBitmap(); + virtual ~X11SalBitmap() override; + + // override pure virtual methods + virtual bool Create( + const Size& rSize, + sal_uInt16 nBitCount, + const BitmapPalette& rPal + ) override; + + virtual bool Create( const SalBitmap& rSalBmp ) override; + virtual bool Create( + const SalBitmap& rSalBmp, + SalGraphics* pGraphics + ) override; + + virtual bool Create( + const SalBitmap& rSalBmp, + sal_uInt16 nNewBitCount + ) override; + + virtual bool Create( + const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false + ) override; + + virtual void Destroy() override; + + virtual Size GetSize() const override; + virtual sal_uInt16 GetBitCount() const override; + + virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override; + virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override; + virtual bool GetSystemData( BitmapSystemData& rData ) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) override; + virtual bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) override; +}; + + +class ImplSalDDB +{ +private: + + Pixmap maPixmap; + SalTwoRect maTwoRect; + long mnDepth; + SalX11Screen mnXScreen; + + static void ImplDraw( + Drawable aSrcDrawable, + long nSrcDrawableDepth, + Drawable aDstDrawable, + long nSrcX, + long nSrcY, + long nDestWidth, + long nDestHeight, + long nDestX, + long nDestY, + const GC& rGC + ); + +public: + + ImplSalDDB( + XImage* pImage, + Drawable aDrawable, + SalX11Screen nXScreen, + const SalTwoRect& rTwoRect + ); + + ImplSalDDB( + Drawable aDrawable, + SalX11Screen nXScreen, + long nDrawableDepth, + long nX, + long nY, + long nWidth, + long nHeight + ); + + ~ImplSalDDB(); + + Pixmap ImplGetPixmap() const { return maPixmap; } + long ImplGetWidth() const { return maTwoRect.mnDestWidth; } + long ImplGetHeight() const { return maTwoRect.mnDestHeight; } + long ImplGetDepth() const { return mnDepth; } + const SalX11Screen& ImplGetScreen() const { return mnXScreen; } + + bool ImplMatches( SalX11Screen nXScreen, long nDepth, const SalTwoRect& rTwoRect ) const; + + void ImplDraw( + Drawable aDrawable, + const SalTwoRect& rTwoRect, + const GC& rGC + ) const; +}; + + +class X11SalBitmap; + +class ImplSalBitmapCache +{ +private: + std::vector maBmpList; + +public: + + ImplSalBitmapCache(); + ~ImplSalBitmapCache(); + + void ImplAdd( X11SalBitmap* pBmp ); + void ImplRemove( X11SalBitmap const * pBmp ); + void ImplClear(); +}; + +#endif // INCLUDED_VCL_INC_UNX_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/saldata.hxx b/vcl/inc/unx/saldata.hxx new file mode 100644 index 000000000..de66ace37 --- /dev/null +++ b/vcl/inc/unx/saldata.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALDATA_HXX +#define INCLUDED_VCL_INC_UNX_SALDATA_HXX + +#include + +#include +#include +#include + +class SalXLib; +class SalDisplay; +class SalPrinter; + +class X11SalData final : public GenericUnixSalData +{ + struct XErrorStackEntry + { + bool m_bIgnore; + bool m_bWas; + XErrorHandler m_aHandler; + }; + std::vector< XErrorStackEntry > m_aXErrorHandlerStack; + XIOErrorHandler m_aOrigXIOErrorHandler; + + std::unique_ptr pXLib_; + +public: + X11SalData( GenericUnixSalDataType t, SalInstance *pInstance ); + virtual ~X11SalData() override; + + virtual void Init(); + virtual void Dispose() override; + + void DeleteDisplay(); // for shutdown + + SalXLib* GetLib() const { return pXLib_.get(); } + + static void Timeout(); + + // X errors + virtual void ErrorTrapPush() override; + virtual bool ErrorTrapPop( bool bIgnoreError = true ) override; + void XError( Display *pDisp, XErrorEvent *pEvent ); + bool HasXErrorOccurred() const + { return m_aXErrorHandlerStack.back().m_bWas; } + void ResetXErrorOccurred() + { m_aXErrorHandlerStack.back().m_bWas = false; } + void PushXErrorLevel( bool bIgnore ); + void PopXErrorLevel(); +}; + +X11SalData* GetX11SalData(); + +#endif // INCLUDED_VCL_INC_UNX_SALDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/saldisp.hxx b/vcl/inc/unx/saldisp.hxx new file mode 100644 index 000000000..b5bed8e60 --- /dev/null +++ b/vcl/inc/unx/saldisp.hxx @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALDISP_HXX +#define INCLUDED_VCL_INC_UNX_SALDISP_HXX + +class SalDisplay; +class SalColormap; +class SalVisual; +class SalXLib; + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* From */ +typedef unsigned long Pixel; + +class BitmapPalette; +class SalFrame; +class ColorMask; + +namespace vcl_sal { class WMAdaptor; } + +// server vendor + +typedef enum { + vendor_none = 0, + vendor_sun, + vendor_unknown +} srv_vendor_t; + +extern "C" srv_vendor_t sal_GetServerVendor( Display *p_display ); + +// MSB/Bigendian view (Color == RGB, r=0xFF0000, g=0xFF00, b=0xFF) + +enum class SalRGB { RGB, RBG, + GBR, GRB, + BGR, BRG, + otherSalRGB }; + +class SalVisual : public XVisualInfo +{ + SalRGB eRGBMode_; + int nRedShift_; + int nGreenShift_; + int nBlueShift_; + int nRedBits_; + int nGreenBits_; + int nBlueBits_; +public: + SalVisual(); + SalVisual( const XVisualInfo* pXVI ); + + VisualID GetVisualId() const { return visualid; } + Visual *GetVisual() const { return visual; } + int GetClass() const { return c_class; } + int GetDepth() const { return depth; } + + Pixel GetTCPixel( Color nColor ) const; + Color GetTCColor( Pixel nPixel ) const; +}; + +// A move-only flag, used by SalColormap to track ownership of its m_aVisual.visual: +struct OwnershipFlag { + bool owner = false; + + OwnershipFlag() = default; + + OwnershipFlag(OwnershipFlag && other) noexcept: owner(other.owner) { other.owner = false; } + + OwnershipFlag & operator =(OwnershipFlag && other) noexcept { + assert(&other != this); + owner = other.owner; + other.owner = false; + return *this; + } +}; + +class SalColormap +{ + const SalDisplay* m_pDisplay; + Colormap m_hColormap; + std::vector m_aPalette; // Pseudocolor + SalVisual m_aVisual; + OwnershipFlag m_aVisualOwnership; + std::vector m_aLookupTable; // Pseudocolor: 12bit reduction + Pixel m_nWhitePixel; + Pixel m_nBlackPixel; + Pixel m_nUsed; // Pseudocolor + + void GetPalette(); + void GetLookupTable(); +public: + SalColormap( const SalDisplay* pSalDisplay, + Colormap hColormap, + SalX11Screen nXScreen ); + SalColormap( sal_uInt16 nDepth ); + SalColormap(); + + ~SalColormap(); + + SalColormap(SalColormap &&) = default; + SalColormap & operator =(SalColormap &&) = default; + + Colormap GetXColormap() const { return m_hColormap; } + const SalDisplay* GetDisplay() const { return m_pDisplay; } + inline Display* GetXDisplay() const; + const SalVisual& GetVisual() const { return m_aVisual; } + Visual* GetXVisual() const { return m_aVisual.GetVisual(); } + Pixel GetWhitePixel() const { return m_nWhitePixel; } + Pixel GetBlackPixel() const { return m_nBlackPixel; } + Pixel GetUsed() const { return m_nUsed; } + + 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( Color nColor ) const; + Color GetColor( Pixel nPixel ) const; +}; + +class SalI18N_InputMethod; + +typedef int(*YieldFunc)(int fd, void* data); + +class SalXLib +{ +protected: + timeval m_aTimeout; + sal_uLong m_nTimeoutMS; + int m_pTimeoutFDS[2]; + + int nFDs_; + fd_set aReadFDS_; + fd_set aExceptionFDS_; + + Display *m_pDisplay; + std::unique_ptr m_pInputMethod; + +public: + SalXLib(); + virtual ~SalXLib(); + virtual void Init(); + + virtual bool Yield( bool bWait, bool bHandleAllCurrentEvents ); + virtual void Wakeup(); + void TriggerUserEventProcessing(); + + virtual void Insert( int fd, void* data, + YieldFunc pending, + YieldFunc queued, + YieldFunc handle ); + virtual void Remove( int fd ); + + virtual void StartTimer( sal_uInt64 nMS ); + virtual void StopTimer(); + + virtual bool CheckTimeout( bool bExecuteTimers = true ); + + SalI18N_InputMethod* GetInputMethod() const { return m_pInputMethod.get(); } + Display* GetDisplay() const { return m_pDisplay; } +}; + +class SalI18N_KeyboardExtension; +class AttributeProvider; + +extern "C" { + typedef Bool(*X_if_predicate)(Display*,XEvent*,XPointer); +} + +class GLX11Window final : public GLWindow +{ +public: + Display* dpy; + int screen; + Window win; + XVisualInfo* vi; + GLXContext ctx; + OString GLXExtensions; + + bool HasGLXExtension(const char* name) const; + + GLX11Window(); + virtual bool Synchronize(bool bOnoff) const override; + virtual ~GLX11Window() override; +}; + +class VCLPLUG_GEN_PUBLIC SalDisplay : public SalGenericDisplay +{ +public: + struct RenderEntry + { + Pixmap m_aPixmap; + Picture m_aPicture; + + RenderEntry() : m_aPixmap( 0 ), m_aPicture( 0 ) {} + }; + + typedef std::unordered_map RenderEntryMap; + + struct ScreenData + { + bool m_bInit; + + ::Window m_aRoot; + ::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 ) + {} + }; + +protected: + SalXLib *pXLib_; + SalI18N_KeyboardExtension *mpKbdExtension; + + Display *pDisp_; // X Display + + SalX11Screen m_nXDefaultScreen; + std::vector< ScreenData > m_aScreens; + ScreenData m_aInvalidScreenData; + Pair aResolution_; // [dpi] + sal_uLong nMaxRequestSize_; // [byte] + + srv_vendor_t meServerVendor; + + // until x bytes + + o3tl::enumarray aPointerCache_; + + // Keyboard + bool bNumLockFromXS_; // Num Lock handled by X Server + int nNumLockIndex_; // modifier index in modmap + KeySym nShiftKeySym_; // first shift modifier + KeySym nCtrlKeySym_; // first control modifier + KeySym nMod1KeySym_; // first mod1 modifier + + std::unique_ptr m_pWMAdaptor; + + bool m_bXinerama; + std::vector< tools::Rectangle > m_aXineramaScreens; + std::vector< int > m_aXineramaScreenIndexMap; + std::list m_aSalObjects; + + mutable Time m_nLastUserEventTime; // mutable because changed on first access + + virtual bool Dispatch( XEvent *pEvent ) = 0; + void InitXinerama(); + void InitRandR( ::Window aRoot ) const; + static void DeInitRandR(); + void processRandREvent( XEvent* ); + + void doDestruct(); + void addXineramaScreenUnique( int i, long i_nX, long i_nY, long i_nWidth, long i_nHeight ); + Time GetEventTimeImpl( bool bAlwaysReget = false ) const; +public: + static bool BestOpenGLVisual(Display* pDisplay, int nScreen, XVisualInfo& rVI); + static bool BestVisual(Display *pDisp, int nScreen, XVisualInfo &rVI); + + SalDisplay( Display* pDisp ); + + virtual ~SalDisplay() override; + + void Init(); + +#ifdef DBG_UTIL + void PrintInfo() const; + void DbgPrintDisplayEvent(const char *pComment, XEvent *pEvent) const; +#endif + + void Beep() const; + + void ModifierMapping(); + void SimulateKeyPress( sal_uInt16 nKeyCode ); + KeyIndicatorState GetIndicatorState() const; + OUString GetKeyNameFromKeySym( KeySym keysym ) const; + OUString GetKeyName( sal_uInt16 nKeyCode ) const; + sal_uInt16 GetKeyCode( KeySym keysym, char*pcPrintable ) const; + KeySym GetKeySym( XKeyEvent *pEvent, + char *pPrintable, + int *pLen, + KeySym *pUnmodifiedKeySym, + Status *pStatus, + XIC = nullptr ) const; + + Cursor GetPointer( PointerStyle ePointerStyle ); + int CaptureMouse( SalFrame *pCapture ); + + ScreenData* initScreen( SalX11Screen nXScreen ) const; + const ScreenData& getDataForScreen( SalX11Screen nXScreen ) const + { + if( nXScreen.getXScreen() >= m_aScreens.size() ) + return m_aInvalidScreenData; + if( ! m_aScreens[nXScreen.getXScreen()].m_bInit ) + initScreen( nXScreen ); + return m_aScreens[nXScreen.getXScreen()]; + } + + ::Window GetDrawable( SalX11Screen nXScreen ) const { return getDataForScreen( nXScreen ).m_aRefWindow; } + Display *GetDisplay() const { return pDisp_; } + const SalX11Screen& GetDefaultXScreen() const { return m_nXDefaultScreen; } + const Size& GetScreenSize( SalX11Screen nXScreen ) const { return getDataForScreen( nXScreen ).m_aSize; } + srv_vendor_t GetServerVendor() const { return meServerVendor; } + bool IsDisplay() const { return !!pXLib_; } + GC GetCopyGC( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aCopyGC; } + Pixmap GetInvert50( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_hInvert50; } + const SalColormap& GetColormap( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aColormap; } + const SalVisual& GetVisual( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aVisual; } + RenderEntryMap& GetRenderEntries( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aRenderData; } + const Pair &GetResolution() const { return aResolution_; } + sal_uLong GetMaxRequestSize() const { return nMaxRequestSize_; } + Time GetLastUserEventTime() const { return GetEventTimeImpl(); } + // this is an equivalent of gdk_x11_get_server_time() + Time GetX11ServerTime() const { return GetEventTimeImpl( true ); } + + bool XIfEventWithTimeout( XEvent*, XPointer, X_if_predicate ) const; + SalXLib* GetXLib() const { return pXLib_; } + + SalI18N_InputMethod* GetInputMethod() const { return pXLib_->GetInputMethod(); } + SalI18N_KeyboardExtension* GetKbdExtension() const { return mpKbdExtension; } + void SetKbdExtension(SalI18N_KeyboardExtension *pKbdExtension) + { mpKbdExtension = pKbdExtension; } + ::vcl_sal::WMAdaptor* getWMAdaptor() const { return m_pWMAdaptor.get(); } + bool IsXinerama() const { return m_bXinerama; } + const std::vector< tools::Rectangle >& GetXineramaScreens() const { return m_aXineramaScreens; } + ::Window GetRootWindow( SalX11Screen nXScreen ) const + { return getDataForScreen( nXScreen ).m_aRoot; } + unsigned int GetXScreenCount() const { return m_aScreens.size(); } + + const SalFrameSet& getFrames() const { return m_aFrames; } + + std::list< SalObject* >& getSalObjects() { return m_aSalObjects; } +}; + +inline Display *SalColormap::GetXDisplay() const +{ return m_pDisplay->GetDisplay(); } + +class SalX11Display final : public SalDisplay +{ +public: + SalX11Display( Display* pDisp ); + virtual ~SalX11Display() override; + + virtual bool Dispatch( XEvent *pEvent ) override; + virtual void Yield(); + virtual void TriggerUserEventProcessing() override; + + bool IsEvent(); + void SetupInput(); +}; + +namespace vcl_sal { + // get foreign key names + OUString getKeysymReplacementName( + const OUString& pLang, + KeySym nSymbol ); + + inline SalDisplay *getSalDisplay(GenericUnixSalData const * data) + { + assert(data != nullptr); + assert(data->GetType() != SAL_DATA_GTK3); + return static_cast(data->GetDisplay()); + } +} + +#endif // INCLUDED_VCL_INC_UNX_SALDISP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salframe.h b/vcl/inc/unx/salframe.h new file mode 100644 index 000000000..4bc756a01 --- /dev/null +++ b/vcl/inc/unx/salframe.h @@ -0,0 +1,270 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALFRAME_H +#define INCLUDED_VCL_INC_UNX_SALFRAME_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +class X11SalGraphics; +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 + +enum class WMWindowType +{ + Normal, + ModelessDialogue, + Utility, + Splash, + Toolbar, + Dock +}; + +class X11SalFrame final : public SalFrame, public NativeWindowHandleProvider +{ + friend class vcl_sal::WMAdaptor; + friend class vcl_sal::NetWMAdaptor; + friend class vcl_sal::GnomeWMAdaptor; + + X11SalFrame* mpParent; // pointer to parent frame + // which should never obscure this frame + bool mbTransientForRoot; + std::list< X11SalFrame* > maChildren; // List of child frames + + SalDisplay *pDisplay_; + SalX11Screen m_nXScreen; + ::Window mhWindow; + ::Window mhShellWindow; + ::Window mhForeignParent; + // window to fall back to when no longer in fullscreen mode + ::Window mhStackingWindow; + // window to listen for CirculateNotify events + + Cursor hCursor_; + int nCaptured_; // is captured + + std::unique_ptr pGraphics_; // current frame graphics + std::unique_ptr pFreeGraphics_; // first free frame graphics + + bool mbSendExtKeyModChange; + ModKeyFlags mnExtKeyMod; + + int nShowState_; // show state + int nWidth_; // client width + int nHeight_; // client height + tools::Rectangle maRestorePosSize; + SalFrameStyleFlags nStyle_; + SalExtStyle mnExtStyle; + bool bAlwaysOnTop_; + bool bViewable_; + bool bMapped_; + bool bDefaultPosition_; // client is centered initially + bool m_bXEmbed; + int nVisibility_; + int m_nWorkArea; + bool m_bSetFocusOnMap; + + ScreenSaverInhibitor maScreenSaverInhibitor; + tools::Rectangle maPaintRegion; + + Timer maAlwaysOnTopRaiseTimer; + + // data for WMAdaptor + WMWindowType meWindowType; + bool mbMaximizedVert; + bool mbMaximizedHorz; + bool mbShaded; + bool mbFullScreen; + + // icon id + int mnIconID; + + OUString m_aTitle; + + OUString m_sWMClass; + + SystemEnvData maSystemChildData; + + std::unique_ptr mpInputContext; + Bool mbInputFocus; + + std::vector m_vClipRectangles; + + bool mPendingSizeEvent; + + void GetPosSize( tools::Rectangle &rPosSize ); + void SetSize ( const Size &rSize ); + void Center(); + void SetPosSize( const tools::Rectangle &rPosSize ); + void Minimize(); + void Maximize(); + void Restore(); + + void RestackChildren( ::Window* pTopLevelWindows, int nTopLevelWindows ); + void RestackChildren(); + + bool HandleKeyEvent ( XKeyEvent *pEvent ); + bool HandleMouseEvent ( XEvent *pEvent ); + bool HandleFocusEvent ( XFocusChangeEvent const *pEvent ); + bool HandleExposeEvent ( XEvent const *pEvent ); + bool HandleSizeEvent ( XConfigureEvent *pEvent ); + bool HandleStateEvent ( XPropertyEvent const *pEvent ); + bool HandleReparentEvent ( XReparentEvent *pEvent ); + bool HandleClientMessage ( XClientMessageEvent*pEvent ); + + DECL_LINK( HandleAlwaysOnTopRaise, Timer*, void ); + + void createNewWindow( ::Window aParent, SalX11Screen nXScreen = SalX11Screen( -1 ) ); + void updateScreenNumber(); + + void setXEmbedInfo(); + void askForXEmbedFocus( sal_Int32 i_nTimeCode ); + + void updateWMClass(); +public: + X11SalFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle, SystemParentData const * pSystemParent = nullptr ); + virtual ~X11SalFrame() override; + + bool Dispatch( XEvent *pEvent ); + void Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nScreen, + SystemParentData const * pParentData, bool bUseGeometry = false ); + + SalDisplay* GetDisplay() const + { + return pDisplay_; + } + Display *GetXDisplay() const + { + return pDisplay_->GetDisplay(); + } + const SalX11Screen& GetScreenNumber() const { return m_nXScreen; } + ::Window GetWindow() const { return mhWindow; } + ::Window GetShellWindow() const { return mhShellWindow; } + ::Window GetForeignParent() const { return mhForeignParent; } + ::Window GetStackingWindow() const { return mhStackingWindow; } + void Close() const { CallCallback( SalEvent::Close, nullptr ); } + SalFrameStyleFlags GetStyle() const { return nStyle_; } + + Cursor GetCursor() const { return hCursor_; } + bool IsCaptured() const { return nCaptured_ == 1; } +#if !defined(__synchronous_extinput__) + void HandleExtTextEvent (XClientMessageEvent const *pEvent); +#endif + bool IsOverrideRedirect() const; + bool IsChildWindow() const { return bool(nStyle_ & (SalFrameStyleFlags::PLUG|SalFrameStyleFlags::SYSTEMCHILD)); } + bool IsSysChildWindow() const { return bool(nStyle_ & SalFrameStyleFlags::SYSTEMCHILD); } + bool IsFloatGrabWindow() const; + SalI18N_InputContext* getInputContext() const { return mpInputContext.get(); } + bool hasFocus() const { return mbInputFocus; } + + void beginUnicodeSequence(); + bool appendUnicodeSequence( sal_Unicode ); + bool endUnicodeSequence(); + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + // 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(std::unique_ptr pData) override; + + virtual void SetTitle( const OUString& rTitle ) override; + virtual void SetIcon( sal_uInt16 nIcon ) override; + virtual void SetMenu( SalMenu* pMenu ) override; + virtual void DrawMenuBar() override; + + virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ) override; + virtual void Show( bool bVisible, bool bNoActivate = false ) override; + virtual void SetMinClientSize( long nWidth, long nHeight ) override; + virtual void SetMaxClientSize( long nWidth, long nHeight ) override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) override; + virtual void GetClientSize( long& rWidth, long& rHeight ) override; + virtual void GetWorkArea( tools::Rectangle& rRect ) override; + virtual SalFrame* GetParent() const override; + virtual void SetWindowState( const SalFrameState* pState ) override; + virtual bool GetWindowState( SalFrameState* pState ) override; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nMonitor ) override; + virtual void StartPresentation( bool bStart ) override; + virtual void SetAlwaysOnTop( bool bOnTop ) override; + virtual void ToTop( SalFrameToTop nFlags ) override; + virtual void SetPointer( PointerStyle ePointerStyle ) override; + virtual void CaptureMouse( bool bMouse ) override; + virtual void SetPointerPos( long nX, long nY ) override; + using SalFrame::Flush; + virtual void Flush() override; + virtual void SetInputContext( SalInputContext* pContext ) override; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) override; + virtual OUString GetKeyName( sal_uInt16 nKeyCode ) override; + virtual bool MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode ) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings( AllSettings& rSettings ) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override; + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) override; + virtual void SetParent( SalFrame* pNewParent ) override; + virtual bool SetPluginParent( SystemParentData* pNewParent ) override; + + virtual void SetScreenNumber( unsigned int ) override; + virtual void SetApplicationID( const OUString &rWMClass ) override; + + // shaped system windows + // set clip region to none (-> rectangular windows, normal state) + virtual void ResetClipRegion() override; + // start setting the clipregion consisting of nRects rectangles + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + // add a rectangle to the clip region + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + // done setting up the clipregion + virtual void EndSetClipRegion() override; + + virtual sal_uIntPtr GetNativeWindowHandle() override; + + /// @internal + void setPendingSizeEvent(); +}; + +#endif // INCLUDED_VCL_INC_UNX_SALFRAME_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h new file mode 100644 index 000000000..4216b703c --- /dev/null +++ b/vcl/inc/unx/salgdi.h @@ -0,0 +1,340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALGDI_H +#define INCLUDED_VCL_INC_UNX_SALGDI_H + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "saltype.h" +#include "saldisp.hxx" + +#include + +/* From */ +typedef unsigned long Pixel; + +class FontAttributes; +class FontSelectPattern; +class SalBitmap; +class SalColormap; +class SalDisplay; +class SalFrame; +class X11Pixmap; +class X11SalVirtualDevice; +class X11SalGraphicsImpl; +class X11OpenGLSalGraphicsImpl; +class X11OpenGLSalVirtualDevice; +class X11SkiaSalVirtualDevice; +class FreetypeFont; +class ImplLayoutArgs; +class PhysicalFontCollection; +class PhysicalFontFace; +class SalGraphicsImpl; +class TextRenderImpl; + +namespace basegfx { + class B2DTrapezoid; +} + +class X11SalGraphics final : public SalGraphics +{ + friend class X11SalGraphicsImpl; + friend class X11OpenGLSalGraphicsImpl; + friend class X11CairoTextRender; + +public: + X11SalGraphics(); + virtual ~X11SalGraphics() COVERITY_NOEXCEPT_FALSE override; + + void Init( SalFrame *pFrame, Drawable aDrawable, SalX11Screen nXScreen ); + void Init( X11SalVirtualDevice *pVirtualDevice, SalColormap* pColormap = nullptr, bool bDeleteColormap = false ); + void Init( X11OpenGLSalVirtualDevice *pVirtualDevice ); + void Init( X11SkiaSalVirtualDevice *pVirtualDevice ); + void DeInit(); + + virtual SalGraphicsImpl* GetImpl() const override; + inline const SalDisplay* GetDisplay() const; + inline Display* GetXDisplay() const; + inline const SalVisual& GetVisual() const; + SalGeometryProvider* GetGeometryProvider() const; + Drawable GetDrawable() const { return hDrawable_; } + void SetDrawable( Drawable d, SalX11Screen nXScreen ); + XRenderPictFormat* GetXRenderFormat() const; + void SetXRenderFormat( XRenderPictFormat* pXRenderFormat ) { m_pXRenderFormat = pXRenderFormat; } + const SalColormap& GetColormap() const { return *m_pColormap; } + + using SalGraphics::GetPixel; + inline Pixel GetPixel( Color nColor ) const; + + const SalX11Screen& GetScreenNumber() const { return m_nXScreen; } + + // override all pure virtual methods + virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override; + virtual sal_uInt16 GetBitCount() const override; + virtual long GetGraphicsWidth() const override; + + virtual void ResetClipRegion() override; + virtual bool setClipRegion( const vcl::Region& ) override; + + virtual void SetLineColor() override; + virtual void SetLineColor( Color nColor ) override; + virtual void SetFillColor() override; + + virtual void SetFillColor( Color nColor ) override; + + virtual void SetXORMode( bool bSet, bool ) override; + + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + + virtual void SetTextColor( Color nColor ) override; + virtual void SetFont(LogicalFontInstance*, int nFallbackLevel) override; + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + virtual FontCharMapRef GetFontCharMap() const override; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const override; + virtual void GetDevFontList( PhysicalFontCollection* ) override; + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) override; + + virtual bool CreateFontSubset( + const OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo ) override; + + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + + virtual void GetGlyphWidths( + const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout( const GenericSalLayout& ) override; + + virtual bool supportsOperation( OutDevSupportType ) const override; + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + + virtual void drawPolyPolygon( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry ) override; + + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override; + +#if 1 // TODO: remove these obsolete methods + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const PolyFlags* pFlgAry ) override; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const PolyFlags* const* pFlgAry ) override; +#endif + + virtual void copyArea( + long nDestX, + long nDestY, + long nSrcX, + long nSrcY, + long nSrcWidth, + long nSrcHeight, + bool bWindowInvalidate ) override; + + virtual void copyBits( + const SalTwoRect& rPosAry, + SalGraphics* pSrcGraphics ) override; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap ) override; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) override; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + virtual Color getPixel( long nX, long nY ) override; + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) override; + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) override; + + virtual bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uInt32 nSize ) override; + + virtual bool blendBitmap( + const SalTwoRect&, + const SalBitmap& rBitmap ) override; + + virtual bool blendAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) override; + + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + + virtual bool drawAlphaRect( + long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) override; + + virtual SystemGraphicsData GetGraphicsData() const override; + +#if ENABLE_CAIRO_CANVAS + virtual bool SupportsCairo() const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const override; + virtual cairo::SurfaceSharedPtr CreateSurface(const OutputDevice& rRefDevice, int x, int y, int width, int height) const override; + virtual cairo::SurfaceSharedPtr CreateBitmapSurface(const OutputDevice& rRefDevice, const BitmapSystemData& rData, const Size& rSize) const override; + virtual css::uno::Any GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const basegfx::B2ISize& rSize) const override; + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const override; + + void clipRegion(cairo_t* cr); +#endif // ENABLE_CAIRO_CANVAS + + /* 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(); + + cairo_t* getCairoContext(); + static void releaseCairoContext(cairo_t* cr); + + +private: + using SalGraphics::SetClipRegion; + void SetClipRegion( GC pGC, Region pXReg = nullptr ) const; + bool GetDitherPixmap ( Color nColor ); + + using SalGraphics::DrawBitmap; + + void freeResources(); + + SalFrame* m_pFrame; // the SalFrame which created this Graphics or NULL + SalVirtualDevice* m_pVDev; // the SalVirtualDevice which created this Graphics or NULL + + const SalColormap* m_pColormap; + std::unique_ptr m_pDeleteColormap; + Drawable hDrawable_; // use + SalX11Screen m_nXScreen; + mutable XRenderPictFormat* m_pXRenderFormat; + XID m_aXRenderPicture; + + Region mpClipRegion; +#if ENABLE_CAIRO_CANVAS + vcl::Region maClipRegion; + Color mnPenColor; + Color mnFillColor; +#endif // ENABLE_CAIRO_CANVAS + + Pixel nTextPixel_; + + Pixmap hBrush_; // Dither + + bool bWindow_ : 1; // is Window + bool bVirDev_ : 1; // is VirDev + bool m_bOpenGL : 1; + bool m_bSkia : 1; + +private: + std::unique_ptr mxImpl; + std::unique_ptr mxTextRenderImpl; + +}; + +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( Color nColor ) const +{ return GetColormap().GetPixel( nColor ); } + +#endif // INCLUDED_VCL_INC_UNX_SALGDI_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salinst.h b/vcl/inc/unx/salinst.h new file mode 100644 index 000000000..89c9a8ae0 --- /dev/null +++ b/vcl/inc/unx/salinst.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALINST_H +#define INCLUDED_VCL_INC_UNX_SALINST_H + +#include +#include +#include + +#include + +namespace com::sun::star::datatransfer { + namespace clipboard { class XClipboard; } +} + +class SalXLib; +class X11SalGraphics; +class SalX11Display; + +class X11SalInstance final : public SalGenericInstance +{ +private: + std::unordered_map< Atom, css::uno::Reference< css::datatransfer::clipboard::XClipboard > > m_aInstances; + + SalXLib *mpXLib; + + virtual SalX11Display* CreateDisplay() const; + +public: + explicit X11SalInstance(std::unique_ptr pMutex); + virtual ~X11SalInstance() override; + + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + virtual void DestroyFrame( SalFrame* pFrame ) override; + + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ) override; + virtual void DestroyObject( SalObject* pObject ) override; + + /// Gtk vclplug needs to pass GtkSalGraphics to X11SalVirtualDevice, so create it, and pass as pNewGraphics. + static std::unique_ptr CreateX11VirtualDevice(SalGraphics const * pGraphics, long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData* pData, std::unique_ptr pNewGraphics); + + virtual std::unique_ptr + CreateVirtualDevice( SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData *pData = nullptr ) override; + virtual void PostPrintersChanged() override; + virtual std::unique_ptr CreatePrintGraphics() override; + + virtual SalTimer* CreateSalTimer() override; + virtual SalSystem* CreateSalSystem() override; + virtual std::shared_ptr CreateSalBitmap() override; + virtual std::unique_ptr CreateSalSession() override; + virtual OpenGLContext* CreateOpenGLContext() override; + + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput( VclInputFlags nType ) override; + virtual bool IsMainThread() const override { return true; } + + virtual OUString GetConnectionIdentifier() override; + void SetLib( SalXLib *pXLib ) { mpXLib = pXLib; } + + virtual void AfterAppInit() override; + + std::shared_ptr GetBackendCapabilities() override; + + // dtrans implementation + virtual css::uno::Reference< css::uno::XInterface > + CreateClipboard( const css::uno::Sequence< css::uno::Any >& i_rArguments ) override; + virtual css::uno::Reference< css::uno::XInterface > CreateDragSource() override; + virtual css::uno::Reference< css::uno::XInterface > CreateDropTarget() override; + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; +}; + +#endif // INCLUDED_VCL_INC_UNX_SALINST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salobj.h b/vcl/inc/unx/salobj.h new file mode 100644 index 000000000..52e4b8f2b --- /dev/null +++ b/vcl/inc/unx/salobj.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALOBJ_H +#define INCLUDED_VCL_INC_UNX_SALOBJ_H + +#include + +#include +#include +#include +#include + +class SalClipRegion +{ + +public: + + SalClipRegion(); + ~SalClipRegion(); + + void BeginSetClipRegion( sal_uInt32 nRects ); + void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ); + + XRectangle *EndSetClipRegion() { + return ClipRectangleList.get(); } + void ResetClipRegion() { + numClipRectangles = 0; } + int GetRectangleCount() const { + return numClipRectangles; } + +private: + + std::unique_ptr + ClipRectangleList; + int numClipRectangles; + int maxClipRectangles; +}; + +class X11SalObject final : public SalObject +{ +public: + SystemEnvData maSystemChildData; + SalFrame* mpParent; + ::Window maParentWin; + ::Window maPrimary; + ::Window maSecondary; + Colormap maColormap; + SalClipRegion maClipRegion; + bool mbVisible; + + static VCL_DLLPUBLIC bool Dispatch( XEvent* pEvent ); + static VCL_DLLPUBLIC X11SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ); + + X11SalObject(); + virtual ~X11SalObject() override; + + // override all pure virtual methods + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + virtual void EndSetClipRegion() override; + + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + virtual void GrabFocus() override; + + virtual void SetLeaveEnterBackgrounds(const css::uno::Sequence& rLeaveArgs, const css::uno::Sequence& rEnterArgs) override; + + virtual const SystemEnvData* GetSystemData() const override; +}; + +#endif // INCLUDED_VCL_INC_UNX_SALOBJ_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/saltimer.h b/vcl/inc/unx/saltimer.h new file mode 100644 index 000000000..c8da2fcac --- /dev/null +++ b/vcl/inc/unx/saltimer.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALTIMER_H +#define INCLUDED_VCL_INC_UNX_SALTIMER_H + +#include + +class SalXLib; +class X11SalTimer final : public SalTimer +{ + SalXLib *mpXLib; +public: + X11SalTimer( SalXLib *pXLib ) : mpXLib( pXLib ) {} + virtual ~X11SalTimer() override; + + // override all pure virtual methods + void Start( sal_uInt64 nMS ) override; + void Stop() override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/saltype.h b/vcl/inc/unx/saltype.h new file mode 100644 index 000000000..e62bdd25e --- /dev/null +++ b/vcl/inc/unx/saltype.h @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +#ifndef INCLUDED_VCL_INC_UNX_SALTYPE_H +#define INCLUDED_VCL_INC_UNX_SALTYPE_H + +// an X11 screen index - this unpleasant construct is to allow +// us to cleanly separate the 'DisplayScreen' concept - as used +// in the public facing API, from X's idea of screen indices. +// Both of these are plain unsigned integers called 'screen' +class SalX11Screen { + unsigned int mnXScreen; +public: + explicit SalX11Screen(unsigned int nXScreen) : mnXScreen( nXScreen ) {} + unsigned int getXScreen() const { return mnXScreen; } + bool operator==(const SalX11Screen &rOther) const { return rOther.mnXScreen == mnXScreen; } + bool operator!=(const SalX11Screen &rOther) const { return rOther.mnXScreen != mnXScreen; } +}; + +#endif // INCLUDED_VCL_INC_UNX_SALTYPE_H +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salunx.h b/vcl/inc/unx/salunx.h new file mode 100644 index 000000000..b70f45769 --- /dev/null +++ b/vcl/inc/unx/salunx.h @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALUNX_H +#define INCLUDED_VCL_INC_UNX_SALUNX_H + +inline long Divide( long nDividend, long nDivisor ) +{ return (nDividend + nDivisor/2) / nDivisor; } + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salunxtime.h b/vcl/inc/unx/salunxtime.h new file mode 100644 index 000000000..13f8ecc35 --- /dev/null +++ b/vcl/inc/unx/salunxtime.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALUNXTIME_H +#define INCLUDED_VCL_INC_UNX_SALUNXTIME_H + +#if defined LINUX || defined FREEBSD || \ + defined NETBSD || defined OPENBSD || defined DRAGONFLY +#include +#elif defined AIX +#include +#include +#include +#endif +#include + +inline bool 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 bool 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, 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, sal_uIntPtr t2 ) +{ + t1.tv_sec += t2 / 1000; + t1.tv_usec += (t2 % 1000) * 1000; + 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; + t0 -= t2; + return t0; +} + +#endif // INCLUDED_VCL_INC_UNX_SALUNXTIME_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salvd.h b/vcl/inc/unx/salvd.h new file mode 100644 index 000000000..b9874a3eb --- /dev/null +++ b/vcl/inc/unx/salvd.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_SALVD_H +#define INCLUDED_VCL_INC_UNX_SALVD_H + +#include + +#include +#include +#include + +#include + +class SalDisplay; +class X11SalGraphics; + +class X11SalVirtualDevice : public SalVirtualDevice +{ + SalDisplay *pDisplay_; + std::unique_ptr pGraphics_; + + Pixmap hDrawable_; + SalX11Screen m_nXScreen; + + int nDX_; + int nDY_; + sal_uInt16 nDepth_; + bool bGraphics_; // is Graphics used + bool bExternPixmap_; + +public: + X11SalVirtualDevice(SalGraphics const *pGraphics, long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData *pData, std::unique_ptr pNewGraphics); + + virtual ~X11SalVirtualDevice() override; + + Display *GetXDisplay() const + { + return pDisplay_->GetDisplay(); + } + SalDisplay *GetDisplay() const + { + return pDisplay_; + } + Pixmap GetDrawable() const { return hDrawable_; } + sal_uInt16 GetDepth() const { return nDepth_; } + const SalX11Screen& GetXScreenNumber() const { return m_nXScreen; } + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + + /// Set new size, without saving the old contents + virtual bool SetSize( long nNewDX, long nNewDY ) override; + + // SalGeometryProvider + virtual long GetWidth() const override { return nDX_; } + virtual long GetHeight() const override { return nDY_; } +}; + +#endif // INCLUDED_VCL_INC_UNX_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/screensaverinhibitor.hxx b/vcl/inc/unx/screensaverinhibitor.hxx new file mode 100644 index 000000000..58c00e7fa --- /dev/null +++ b/vcl/inc/unx/screensaverinhibitor.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_SCREENSAVERINHIBITOR_HXX +#define INCLUDED_VCL_INC_UNX_SCREENSAVERINHIBITOR_HXX + +#include +#include + +#include +#include + +#include + +class VCL_PLUGIN_PUBLIC ScreenSaverInhibitor +{ +public: + void inhibit( bool bInhibit, const OUString& sReason, + bool bIsX11, const std::optional& xid, std::optional pDisplay ); + +private: + // These are all used as guint, however this header may be included + // in kde/tde/etc backends, where we would ideally avoid having + // any glib dependencies, hence the direct use of unsigned int. + std::optional mnFDOCookie; // FDO ScreenSaver Inhibit + std::optional mnFDOPMCookie; // FDO PowerManagement Inhibit + std::optional mnGSMCookie; + std::optional mnMSMCookie; + + std::optional mnXScreenSaverTimeout; + +#if !defined(__sun) && !defined(AIX) + BOOL mbDPMSWasEnabled; + CARD16 mnDPMSStandbyTimeout; + CARD16 mnDPMSSuspendTimeout; + CARD16 mnDPMSOffTimeout; +#endif + + // There are a bunch of different dbus based inhibition APIs. Some call + // themselves ScreenSaver inhibition, some are PowerManagement inhibition, + // but they appear to have the same effect. There doesn't appear to be one + // all encompassing standard, hence we should just try all of them. + // + // The current APIs we have: (note: the list of supported environments is incomplete) + // FDO: org.freedesktop.ScreenSaver::Inhibit - appears to be supported only by KDE? + // FDOPM: org.freedesktop.PowerManagement.Inhibit::Inhibit - XFCE, (KDE) ? + // (KDE: doesn't inhibit screensaver, but does inhibit PowerManagement) + // GSM: org.gnome.SessionManager::Inhibit - gnome 3 + // MSM: org.mate.Sessionmanager::Inhibit - Mate <= 1.10, is identical to GSM + // (This is replaced by the GSM interface from Mate 1.12 onwards) + // + // Note: the Uninhibit call has different spelling in FDO (UnInhibit) vs GSM (Uninhibit) + void inhibitFDO( bool bInhibit, const char* appname, const char* reason ); + void inhibitFDOPM( bool bInhibit, const char* appname, const char* reason ); + void inhibitGSM( bool bInhibit, const char* appname, const char* reason, const unsigned int xid ); + void inhibitMSM( bool bInhibit, const char* appname, const char* reason, const unsigned int xid ); + + void inhibitXScreenSaver( bool bInhibit, Display* pDisplay ); + static void inhibitXAutoLock( bool bInhibit, Display* pDisplay ); + void inhibitDPMS( bool bInhibit, Display* pDisplay ); +}; + +#endif // INCLUDED_VCL_INC_UNX_SCREENSAVERINHIBITOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/sm.hxx b/vcl/inc/unx/sm.hxx new file mode 100644 index 000000000..164fd4f6d --- /dev/null +++ b/vcl/inc/unx/sm.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_INC_UNX_SM_HXX +#define INCLUDED_VCL_INC_UNX_SM_HXX + +#include + +#include + +#include +#include +#include + +#include + +class ICEConnectionObserver; +class SalSession; + +class SessionManagerClient +{ + static SalSession * m_pSession; + static std::unique_ptr< ICEConnectionObserver > m_xICEConnectionObserver; + static SmcConn m_pSmcConnection; + static OString m_aClientID; + static OString m_aTimeID; + static OString m_aClientTimeID; + static bool m_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 OString getPreviousSessionID(); + + DECL_STATIC_LINK( SessionManagerClient, ShutDownHdl, void*, void ); + DECL_STATIC_LINK( SessionManagerClient, ShutDownCancelHdl, void*, void ); + DECL_STATIC_LINK( SessionManagerClient, SaveYourselfHdl, void*, void ); + DECL_STATIC_LINK( SessionManagerClient, InteractionHdl, void*, void ); +public: + static void open(SalSession * pSession); + static void close(); + + static bool checkDocumentsSaved(); + static bool queryInteraction(); + static void saveDone(); + static void interactionDone( bool bCancelShutdown ); + + static OUString getExecName(); + static const OString& getSessionID(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/svsys.h b/vcl/inc/unx/svsys.h new file mode 100644 index 000000000..174a1ed74 --- /dev/null +++ b/vcl/inc/unx/svsys.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_VCL_INC_UNX_SVSYS_H +#define INCLUDED_VCL_INC_UNX_SVSYS_H + +#include +#include +#include +#include + +#endif // INCLUDED_VCL_INC_UNX_SVSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/wmadaptor.hxx b/vcl/inc/unx/wmadaptor.hxx new file mode 100644 index 000000000..1739053a0 --- /dev/null +++ b/vcl/inc/unx/wmadaptor.hxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_WMADAPTOR_HXX +#define INCLUDED_VCL_INC_UNX_WMADAPTOR_HXX + +#include +#include + +#include + +#include +#include "salframe.h" +#include + +class SalDisplay; +class X11SalFrame; + +namespace vcl_sal { + +class WMAdaptor +{ +public: + enum WMAtom { + // atoms for types + UTF8_STRING, + + // atoms for extended WM hints + NET_ACTIVE_WINDOW, + 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, + NET_WM_ICON, + + // 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_CLIENT_LIST, + + // atoms for general WM hints + WM_STATE, + MOTIF_WM_HINTS, + WM_PROTOCOLS, + WM_DELETE_WINDOW, + WM_TAKE_FOCUS, + WM_CLIENT_LEADER, + WM_COMMAND, + WM_LOCALE_NAME, + WM_TRANSIENT_FOR, + + // special atoms + SAL_QUITEVENT, + SAL_USEREVENT, + SAL_EXTTEXTEVENT, + SAL_GETTIMEEVENT, + 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; + +protected: + SalDisplay* m_pSalDisplay; // Display to use + Display* m_pDisplay; // X Display of SalDisplay + OUString m_aWMName; + Atom m_aWMAtoms[ NetAtomMax]; + int m_nDesktops; + bool m_bEqualWorkAreas; + ::std::vector< tools::Rectangle > + m_aWMWorkAreas; + bool m_bEnableAlwaysOnTopWorks; + bool m_bLegacyPartialFullscreen; + int m_nWinGravity; + int m_nInitWinGravity; + bool m_bWMshouldSwitchWorkspace; + bool m_bWMshouldSwitchWorkspaceInit; + + WMAdaptor( SalDisplay * ) +; + void initAtoms(); + bool getNetWmName(); + + /* + * returns whether this instance is useful + * only useful for createWMAdaptor + */ + virtual bool isValid() const; + + bool getWMshouldSwitchWorkspace() const; +public: + virtual ~WMAdaptor(); + + /* + * creates a valid WMAdaptor instance for the SalDisplay + */ + static std::unique_ptr createWMAdaptor( SalDisplay* ); + + /* + * may return an empty string if the window manager could + * not be identified. + */ + const OUString& getWindowManagerName() const + { return m_aWMName; } + + /* + * 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( ::Window aWindow ) const; + /* + * gets the specified workarea + */ + const tools::Rectangle& getWorkArea( int n ) const + { return m_aWMWorkAreas[n]; } + + /* + * attempt to switch the desktop to a certain workarea (ie. virtual desktops) + */ + void switchToWorkArea( int nWorkArea ) const; + + /* + * sets window title + */ + virtual void setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const; + + /* + * set NET_WM_PID + */ + void setPID( X11SalFrame const * pFrame ) const; + + /* + * set WM_CLIENT_MACHINE + */ + void setClientMachine( X11SalFrame const * pFrame ) const; + + void answerPing( X11SalFrame const *, XClientMessageEvent const * ) 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 account and honor the positioning hints + * to see which screen actually was meant to use for fullscreen. + */ + bool isLegacyPartialFullscreen() const + { return m_bLegacyPartialFullscreen; } + /* + * 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 ) const; + + /* + * tells whether there is WM support for splash screens + */ + bool supportsSplash() const { return m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] != 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 ]; } + + int getPositionWinGravity () const + { return m_nWinGravity; } + int getInitWinGravity() const + { return m_nInitWinGravity; } + + /* + * 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 const * pReferenceFrame ) const; + + /* + * Requests the change of active window by sending + * _NET_ACTIVE_WINDOW message to the frame. The frame + * has to be mapped + */ + void activateWindow( X11SalFrame const *pFrame, Time nTimestamp ); +}; + +} // namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11/x11cairotextrender.hxx b/vcl/inc/unx/x11/x11cairotextrender.hxx new file mode 100644 index 000000000..666f09f8c --- /dev/null +++ b/vcl/inc/unx/x11/x11cairotextrender.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_UNX_GENERIC_GDI_X11CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_UNX_GENERIC_GDI_X11CAIROTEXTRENDER_HXX + +#include +#include + +class X11CairoTextRender : public CairoTextRender +{ +protected: + X11SalGraphics& mrParent; + +protected: + size_t GetWidth() const; + size_t GetHeight() const; + +public: + explicit X11CairoTextRender(X11SalGraphics& rParent); + + virtual cairo_t* getCairoContext() override; + virtual void getSurfaceOffset(double& nDX, double& nDY) override; + virtual void clipRegion(cairo_t* cr) override; + virtual void releaseCairoContext(cairo_t* cr) override; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11/x11gdiimpl.h b/vcl/inc/unx/x11/x11gdiimpl.h new file mode 100644 index 000000000..2e41e87c8 --- /dev/null +++ b/vcl/inc/unx/x11/x11gdiimpl.h @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX +#define INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX + +#include + +class ControlCacheKey; + +class X11GraphicsImpl +{ +public: + virtual ~X11GraphicsImpl() {}; +}; + +#endif // INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11/x11sys.hxx b/vcl/inc/unx/x11/x11sys.hxx new file mode 100644 index 000000000..dcbe45928 --- /dev/null +++ b/vcl/inc/unx/x11/x11sys.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_X11_X11SYS_HXX +#define INCLUDED_VCL_INC_UNX_X11_X11SYS_HXX + +#include +#include + +class X11SalSystem final : public SalGenericSystem +{ +public: + X11SalSystem() {} + virtual ~X11SalSystem() override; + + // override pure virtual methods + virtual unsigned int GetDisplayScreenCount() override; + virtual bool IsUnifiedDisplay() override; + virtual unsigned int GetDisplayBuiltInScreen() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ) override; + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) override; +}; + +#endif // INCLUDED_VCL_INC_UNX_X11_X11SYS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11/xlimits.hxx b/vcl/inc/unx/x11/xlimits.hxx new file mode 100644 index 000000000..b46ff9bb1 --- /dev/null +++ b/vcl/inc/unx/x11/xlimits.hxx @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_X11_XLIMITS_HXX +#define INCLUDED_VCL_INC_UNX_X11_XLIMITS_HXX + +#include +#include + +Pixmap limitXCreatePixmap(Display *display, Drawable d, unsigned int width, unsigned int height, unsigned int depth); + +#endif // INCLUDED_VCL_INC_UNX_X11_XLIMITS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11/xrender_peer.hxx b/vcl/inc/unx/x11/xrender_peer.hxx new file mode 100644 index 000000000..e1006f88e --- /dev/null +++ b/vcl/inc/unx/x11/xrender_peer.hxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_UNX_X11_XRENDER_PEER_HXX +#define INCLUDED_VCL_UNX_X11_XRENDER_PEER_HXX + +#include +#include +struct _XTrap; // on some older systems this is not declared within Xrender.h +#include + +#include + + +class XRenderPeer +{ +public: + static XRenderPeer& GetInstance(); + +private: + XRenderPeer(); + void InitRenderLib(); + + Display* mpDisplay; + XRenderPictFormat* mpStandardFormatA8; + +public: + XRenderPictFormat* GetStandardFormatA8() const; + XRenderPictFormat* FindStandardFormat(int nFormat) const; + + // the methods below are thin wrappers for the XRENDER API + XRenderPictFormat* FindVisualFormat( Visual const * ) const; + Picture CreatePicture( Drawable, const XRenderPictFormat*, + unsigned long nDrawable, const XRenderPictureAttributes* ) const; + void ChangePicture( Picture, unsigned long nValueMask, + const XRenderPictureAttributes* ) const; + void SetPictureClipRegion( Picture, Region ) const; + void CompositePicture( int nOp, Picture aSrc, Picture aMask, Picture aDst, + int nXSrc, int nYSrc, + int nXDst, int nYDst, unsigned nWidth, unsigned nHeight ) const; + void FreePicture( Picture ) 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; + void CompositeTriangles( int nOp, Picture aSrc, Picture aDst, + const XRenderPictFormat*, int nXSrc, int nYSrc, + const XTriangle*, int nCount ) const; +}; + +inline XRenderPictFormat* XRenderPeer::GetStandardFormatA8() const +{ + return mpStandardFormatA8; +} + +inline XRenderPictFormat* XRenderPeer::FindStandardFormat(int nFormat) const +{ + return XRenderFindStandardFormat(mpDisplay, nFormat); +} + +inline XRenderPictFormat* XRenderPeer::FindVisualFormat( Visual const * pVisual ) const +{ + return XRenderFindVisualFormat ( mpDisplay, pVisual ); +} + +inline Picture XRenderPeer::CreatePicture( Drawable aDrawable, + const XRenderPictFormat* pVisFormat, unsigned long nValueMask, + const XRenderPictureAttributes* pRenderAttr ) const +{ + return XRenderCreatePicture( mpDisplay, aDrawable, pVisFormat, + nValueMask, pRenderAttr ); +} + +inline void XRenderPeer::ChangePicture( Picture aPicture, + unsigned long nValueMask, const XRenderPictureAttributes* pRenderAttr ) const +{ + XRenderChangePicture( mpDisplay, aPicture, nValueMask, pRenderAttr ); +} + +inline void XRenderPeer::SetPictureClipRegion( Picture aPicture, + Region aXlibRegion ) const +{ + XRenderSetPictureClipRegion( mpDisplay, aPicture, aXlibRegion ); +} + +inline void XRenderPeer::CompositePicture( int nXRenderOp, + Picture aSrcPic, Picture aMaskPic, Picture aDstPic, + int nSrcX, int nSrcY, int nDstX, int nDstY, + unsigned nWidth, unsigned nHeight ) const +{ + XRenderComposite( mpDisplay, nXRenderOp, aSrcPic, aMaskPic, aDstPic, + nSrcX, nSrcY, 0/*nMaskX*/, 0/*nMaskY*/, nDstX, nDstY, nWidth, nHeight ); +} + +inline void XRenderPeer::FreePicture( Picture aPicture ) const +{ + XRenderFreePicture( mpDisplay, aPicture ); +} + +inline void XRenderPeer::FillRectangle( int a, Picture b, const XRenderColor* c, + int d, int e, unsigned int f, unsigned int g) const +{ + XRenderFillRectangle( mpDisplay, a, b, c, d, e, f, g ); +} + +inline void XRenderPeer::CompositeTrapezoids( int nOp, + Picture aSrc, Picture aDst, const XRenderPictFormat* pXRPF, + int nXSrc, int nYSrc, const XTrapezoid* pXT, int nCount ) const +{ + XRenderCompositeTrapezoids( mpDisplay, nOp, aSrc, aDst, pXRPF, + nXSrc, nYSrc, pXT, nCount ); +} + +inline void XRenderPeer::CompositeTriangles( int nOp, + Picture aSrc, Picture aDst, const XRenderPictFormat* pXRPF, + int nXSrc, int nYSrc, const XTriangle* pXT, int nCount ) const +{ + XRenderCompositeTriangles( mpDisplay, nOp, aSrc, aDst, pXRPF, + nXSrc, nYSrc, pXT, nCount ); +} + +inline XRenderColor GetXRenderColor( Color rColor, double fTransparency ) +{ + XRenderColor aRetVal; + // convert the Color + aRetVal.red = rColor.GetRed(); aRetVal.red |= (aRetVal.red << 8); + aRetVal.green = rColor.GetGreen(); aRetVal.green |= (aRetVal.green << 8); + aRetVal.blue = rColor.GetBlue(); 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(fAlpha * 0xFFFF + 0.5); + // xrender wants pre-multiplied colors + aRetVal.red = static_cast(fAlpha * aRetVal.red + 0.5); + aRetVal.green = static_cast(fAlpha * aRetVal.green + 0.5); + aRetVal.blue = static_cast(fAlpha * aRetVal.blue + 0.5); + } + + return aRetVal; +} + +#endif // INCLUDED_VCL_UNX_X11_XRENDER_PEER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/ase_curs.h b/vcl/inc/unx/x11_cursors/ase_curs.h new file mode 100644 index 000000000..878d1ff57 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/ase_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define ase_curs_width 32 +#define ase_curs_height 32 +#define ase_curs_x_hot 19 +#define ase_curs_y_hot 16 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/ase_mask.h b/vcl/inc/unx/x11_cursors/ase_mask.h new file mode 100644 index 000000000..258b2bc93 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/ase_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define ase_mask_width 32 +#define ase_mask_height 32 +#define ase_mask_x_hot 19 +#define ase_mask_y_hot 16 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asn_curs.h b/vcl/inc/unx/x11_cursors/asn_curs.h new file mode 100644 index 000000000..1e6170af4 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asn_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asn_curs_width 32 +#define asn_curs_height 32 +#define asn_curs_x_hot 16 +#define asn_curs_y_hot 12 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asn_mask.h b/vcl/inc/unx/x11_cursors/asn_mask.h new file mode 100644 index 000000000..c44b5eeb9 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asn_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asn_mask_width 32 +#define asn_mask_height 32 +#define asn_mask_x_hot 16 +#define asn_mask_y_hot 12 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asne_curs.h b/vcl/inc/unx/x11_cursors/asne_curs.h new file mode 100644 index 000000000..cc757474e --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asne_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asne_curs_width 32 +#define asne_curs_height 32 +#define asne_curs_x_hot 21 +#define asne_curs_y_hot 10 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asne_mask.h b/vcl/inc/unx/x11_cursors/asne_mask.h new file mode 100644 index 000000000..ebb80c0ba --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asne_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asne_mask_width 32 +#define asne_mask_height 32 +#define asne_mask_x_hot 21 +#define asne_mask_y_hot 10 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asns_curs.h b/vcl/inc/unx/x11_cursors/asns_curs.h new file mode 100644 index 000000000..27c0ce7e7 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asns_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asns_curs_width 32 +#define asns_curs_height 32 +#define asns_curs_x_hot 15 +#define asns_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asns_mask.h b/vcl/inc/unx/x11_cursors/asns_mask.h new file mode 100644 index 000000000..d7d8a1253 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asns_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asns_mask_width 32 +#define asns_mask_height 32 +#define asns_mask_x_hot 15 +#define asns_mask_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asnswe_curs.h b/vcl/inc/unx/x11_cursors/asnswe_curs.h new file mode 100644 index 000000000..e746fc59b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asnswe_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asnswe_curs_width 32 +#define asnswe_curs_height 32 +#define asnswe_curs_x_hot 15 +#define asnswe_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asnswe_mask.h b/vcl/inc/unx/x11_cursors/asnswe_mask.h new file mode 100644 index 000000000..69bb087d3 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asnswe_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asnswe_mask_width 32 +#define asnswe_mask_height 32 +#define asnswe_mask_x_hot 15 +#define asnswe_mask_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asnw_curs.h b/vcl/inc/unx/x11_cursors/asnw_curs.h new file mode 100644 index 000000000..67df6fb7b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asnw_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asnw_curs_width 32 +#define asnw_curs_height 32 +#define asnw_curs_x_hot 10 +#define asnw_curs_y_hot 10 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asnw_mask.h b/vcl/inc/unx/x11_cursors/asnw_mask.h new file mode 100644 index 000000000..15bc43bcf --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asnw_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asnw_mask_width 32 +#define asnw_mask_height 32 +#define asnw_mask_x_hot 10 +#define asnw_mask_y_hot 10 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/ass_curs.h b/vcl/inc/unx/x11_cursors/ass_curs.h new file mode 100644 index 000000000..4335c1821 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/ass_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define ass_curs_width 32 +#define ass_curs_height 32 +#define ass_curs_x_hot 15 +#define ass_curs_y_hot 19 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/ass_mask.h b/vcl/inc/unx/x11_cursors/ass_mask.h new file mode 100644 index 000000000..1ba699bc4 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/ass_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define ass_mask_width 32 +#define ass_mask_height 32 +#define ass_mask_x_hot 15 +#define ass_mask_y_hot 19 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asse_curs.h b/vcl/inc/unx/x11_cursors/asse_curs.h new file mode 100644 index 000000000..ea3607bea --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asse_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asse_curs_width 32 +#define asse_curs_height 32 +#define asse_curs_x_hot 21 +#define asse_curs_y_hot 21 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asse_mask.h b/vcl/inc/unx/x11_cursors/asse_mask.h new file mode 100644 index 000000000..3d366d8e1 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asse_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asse_mask_width 32 +#define asse_mask_height 32 +#define asse_mask_x_hot 21 +#define asse_mask_y_hot 21 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/assw_curs.h b/vcl/inc/unx/x11_cursors/assw_curs.h new file mode 100644 index 000000000..fe5645c28 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/assw_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define assw_curs_width 32 +#define assw_curs_height 32 +#define assw_curs_x_hot 10 +#define assw_curs_y_hot 21 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/assw_mask.h b/vcl/inc/unx/x11_cursors/assw_mask.h new file mode 100644 index 000000000..959a0600c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/assw_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define assw_mask_width 32 +#define assw_mask_height 32 +#define assw_mask_x_hot 10 +#define assw_mask_y_hot 21 +static unsigned 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,0x0E,0x00, + 0x00,0x00,0x1F,0x00,0x00,0x80,0x3F,0x00,0x00,0x90,0x3F,0x00,0x00,0xB8,0x3F, + 0x00,0x00,0x3C,0x1F,0x00,0x00,0x7C,0x0E,0x00,0x00,0xFC,0x00,0x00,0x00,0xFE, + 0x03,0x00,0x00,0xFE,0x07,0x00,0x00,0xFE,0x03,0x00,0x00,0xFE,0x01,0x00,0x00, + 0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asw_curs.h b/vcl/inc/unx/x11_cursors/asw_curs.h new file mode 100644 index 000000000..b3b4a56c4 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asw_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asw_curs_width 32 +#define asw_curs_height 32 +#define asw_curs_x_hot 12 +#define asw_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/asw_mask.h b/vcl/inc/unx/x11_cursors/asw_mask.h new file mode 100644 index 000000000..ad85d47f7 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/asw_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define asw_mask_width 32 +#define asw_mask_height 32 +#define asw_mask_x_hot 12 +#define asw_mask_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/aswe_curs.h b/vcl/inc/unx/x11_cursors/aswe_curs.h new file mode 100644 index 000000000..0f7ed0fc1 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/aswe_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define aswe_curs_width 32 +#define aswe_curs_height 32 +#define aswe_curs_x_hot 15 +#define aswe_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/aswe_mask.h b/vcl/inc/unx/x11_cursors/aswe_mask.h new file mode 100644 index 000000000..24e105058 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/aswe_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define aswe_mask_width 32 +#define aswe_mask_height 32 +#define aswe_mask_x_hot 15 +#define aswe_mask_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chain_curs.h b/vcl/inc/unx/x11_cursors/chain_curs.h new file mode 100644 index 000000000..26c055225 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chain_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chain_curs_width 32 +#define chain_curs_height 32 +#define chain_curs_x_hot 0 +#define chain_curs_y_hot 2 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chain_mask.h b/vcl/inc/unx/x11_cursors/chain_mask.h new file mode 100644 index 000000000..4b25c9c4b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chain_mask.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chain_mask_width 32 +#define chain_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chainnot_curs.h b/vcl/inc/unx/x11_cursors/chainnot_curs.h new file mode 100644 index 000000000..9af6f79d3 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chainnot_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chainnot_curs_width 32 +#define chainnot_curs_height 32 +#define chainnot_curs_x_hot 2 +#define chainnot_curs_y_hot 2 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chainnot_mask.h b/vcl/inc/unx/x11_cursors/chainnot_mask.h new file mode 100644 index 000000000..e5e24e0c7 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chainnot_mask.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chainnot_mask_width 32 +#define chainnot_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chart_curs.h b/vcl/inc/unx/x11_cursors/chart_curs.h new file mode 100644 index 000000000..367f6b05c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chart_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chart_curs_width 32 +#define chart_curs_height 32 +#define chart_curs_x_hot 15 +#define chart_curs_y_hot 16 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/chart_mask.h b/vcl/inc/unx/x11_cursors/chart_mask.h new file mode 100644 index 000000000..6f6977062 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/chart_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define chart_mask_width 32 +#define chart_mask_height 32 +#define chart_mask_x_hot 15 +#define chart_mask_y_hot 16 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copydata_curs.h b/vcl/inc/unx/x11_cursors/copydata_curs.h new file mode 100644 index 000000000..4cc36ebde --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copydata_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copydata_curs_width 32 +#define copydata_curs_height 32 +#define copydata_curs_x_hot 1 +#define copydata_curs_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copydata_mask.h b/vcl/inc/unx/x11_cursors/copydata_mask.h new file mode 100644 index 000000000..a3538c952 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copydata_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copydata_mask_width 32 +#define copydata_mask_height 32 +#define copydata_mask_x_hot 1 +#define copydata_mask_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copydlnk_curs.h b/vcl/inc/unx/x11_cursors/copydlnk_curs.h new file mode 100644 index 000000000..df05429e9 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copydlnk_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copydlnk_curs_width 32 +#define copydlnk_curs_height 32 +#define copydlnk_curs_x_hot 1 +#define copydlnk_curs_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copydlnk_mask.h b/vcl/inc/unx/x11_cursors/copydlnk_mask.h new file mode 100644 index 000000000..b2ffcca62 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copydlnk_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copydlnk_mask_width 32 +#define copydlnk_mask_height 32 +#define copydlnk_mask_x_hot 1 +#define copydlnk_mask_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyfile_curs.h b/vcl/inc/unx/x11_cursors/copyfile_curs.h new file mode 100644 index 000000000..22d9fc6ff --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyfile_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyfile_curs_width 32 +#define copyfile_curs_height 32 +#define copyfile_curs_x_hot 9 +#define copyfile_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyfile_mask.h b/vcl/inc/unx/x11_cursors/copyfile_mask.h new file mode 100644 index 000000000..171d8b7bc --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyfile_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyfile_mask_width 32 +#define copyfile_mask_height 32 +#define copyfile_mask_x_hot 9 +#define copyfile_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyfiles_curs.h b/vcl/inc/unx/x11_cursors/copyfiles_curs.h new file mode 100644 index 000000000..2a8041795 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyfiles_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyfiles_curs_width 32 +#define copyfiles_curs_height 32 +#define copyfiles_curs_x_hot 8 +#define copyfiles_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyfiles_mask.h b/vcl/inc/unx/x11_cursors/copyfiles_mask.h new file mode 100644 index 000000000..02f2d4c12 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyfiles_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyfiles_mask_width 32 +#define copyfiles_mask_height 32 +#define copyfiles_mask_x_hot 8 +#define copyfiles_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyflnk_curs.h b/vcl/inc/unx/x11_cursors/copyflnk_curs.h new file mode 100644 index 000000000..43629e23a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyflnk_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyflnk_curs_width 32 +#define copyflnk_curs_height 32 +#define copyflnk_curs_x_hot 9 +#define copyflnk_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/copyflnk_mask.h b/vcl/inc/unx/x11_cursors/copyflnk_mask.h new file mode 100644 index 000000000..cd17b334c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/copyflnk_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define copyflnk_mask_width 32 +#define copyflnk_mask_height 32 +#define copyflnk_mask_x_hot 9 +#define copyflnk_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/crook_curs.h b/vcl/inc/unx/x11_cursors/crook_curs.h new file mode 100644 index 000000000..989d43b54 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/crook_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define crook_curs_width 32 +#define crook_curs_height 32 +#define crook_curs_x_hot 15 +#define crook_curs_y_hot 14 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/crook_mask.h b/vcl/inc/unx/x11_cursors/crook_mask.h new file mode 100644 index 000000000..6e30897e5 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/crook_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define crook_mask_width 32 +#define crook_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/crop_curs.h b/vcl/inc/unx/x11_cursors/crop_curs.h new file mode 100644 index 000000000..f40842257 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/crop_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define crop_curs_width 32 +#define crop_curs_height 32 +#define crop_curs_x_hot 9 +#define crop_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/crop_mask.h b/vcl/inc/unx/x11_cursors/crop_mask.h new file mode 100644 index 000000000..10d3598af --- /dev/null +++ b/vcl/inc/unx/x11_cursors/crop_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define crop_mask_width 32 +#define crop_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/detective_curs.h b/vcl/inc/unx/x11_cursors/detective_curs.h new file mode 100644 index 000000000..265be0fa2 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/detective_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define detective_curs_width 32 +#define detective_curs_height 32 +#define detective_curs_x_hot 12 +#define detective_curs_y_hot 13 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/detective_mask.h b/vcl/inc/unx/x11_cursors/detective_mask.h new file mode 100644 index 000000000..411e8a39d --- /dev/null +++ b/vcl/inc/unx/x11_cursors/detective_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define detective_mask_width 32 +#define detective_mask_height 32 +#define detective_mask_x_hot 12 +#define detective_mask_y_hot 13 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawarc_curs.h b/vcl/inc/unx/x11_cursors/drawarc_curs.h new file mode 100644 index 000000000..17edc92db --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawarc_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawarc_curs_width 32 +#define drawarc_curs_height 32 +#define drawarc_curs_x_hot 7 +#define drawarc_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawarc_mask.h b/vcl/inc/unx/x11_cursors/drawarc_mask.h new file mode 100644 index 000000000..6c0c01754 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawarc_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawarc_mask_width 32 +#define drawarc_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawbezier_curs.h b/vcl/inc/unx/x11_cursors/drawbezier_curs.h new file mode 100644 index 000000000..5470e8d6d --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawbezier_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawbezier_curs_width 32 +#define drawbezier_curs_height 32 +#define drawbezier_curs_x_hot 7 +#define drawbezier_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawbezier_mask.h b/vcl/inc/unx/x11_cursors/drawbezier_mask.h new file mode 100644 index 000000000..b3b128261 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawbezier_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawbezier_mask_width 32 +#define drawbezier_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawcaption_curs.h b/vcl/inc/unx/x11_cursors/drawcaption_curs.h new file mode 100644 index 000000000..d16c2103b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawcaption_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawcaption_curs_width 32 +#define drawcaption_curs_height 32 +#define drawcaption_curs_x_hot 8 +#define drawcaption_curs_y_hot 8 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawcaption_mask.h b/vcl/inc/unx/x11_cursors/drawcaption_mask.h new file mode 100644 index 000000000..24a6643a0 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawcaption_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawcaption_mask_width 32 +#define drawcaption_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawcirclecut_curs.h b/vcl/inc/unx/x11_cursors/drawcirclecut_curs.h new file mode 100644 index 000000000..35939eb26 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawcirclecut_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawcirclecut_curs_width 32 +#define drawcirclecut_curs_height 32 +#define drawcirclecut_curs_x_hot 7 +#define drawcirclecut_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawcirclecut_mask.h b/vcl/inc/unx/x11_cursors/drawcirclecut_mask.h new file mode 100644 index 000000000..eeead07a4 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawcirclecut_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawcirclecut_mask_width 32 +#define drawcirclecut_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawconnect_curs.h b/vcl/inc/unx/x11_cursors/drawconnect_curs.h new file mode 100644 index 000000000..adad711d1 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawconnect_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawconnect_curs_width 32 +#define drawconnect_curs_height 32 +#define drawconnect_curs_x_hot 7 +#define drawconnect_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawconnect_mask.h b/vcl/inc/unx/x11_cursors/drawconnect_mask.h new file mode 100644 index 000000000..566a134c7 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawconnect_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawconnect_mask_width 32 +#define drawconnect_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawellipse_curs.h b/vcl/inc/unx/x11_cursors/drawellipse_curs.h new file mode 100644 index 000000000..36e886263 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawellipse_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawellipse_curs_width 32 +#define drawellipse_curs_height 32 +#define drawellipse_curs_x_hot 7 +#define drawellipse_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawellipse_mask.h b/vcl/inc/unx/x11_cursors/drawellipse_mask.h new file mode 100644 index 000000000..304db762b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawellipse_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawellipse_mask_width 32 +#define drawellipse_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawfreehand_curs.h b/vcl/inc/unx/x11_cursors/drawfreehand_curs.h new file mode 100644 index 000000000..b00d9be98 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawfreehand_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawfreehand_curs_width 32 +#define drawfreehand_curs_height 32 +#define drawfreehand_curs_x_hot 8 +#define drawfreehand_curs_y_hot 8 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawfreehand_mask.h b/vcl/inc/unx/x11_cursors/drawfreehand_mask.h new file mode 100644 index 000000000..0e5d38ebd --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawfreehand_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawfreehand_mask_width 32 +#define drawfreehand_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawline_curs.h b/vcl/inc/unx/x11_cursors/drawline_curs.h new file mode 100644 index 000000000..5376a6600 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawline_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawline_curs_width 32 +#define drawline_curs_height 32 +#define drawline_curs_x_hot 7 +#define drawline_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawline_mask.h b/vcl/inc/unx/x11_cursors/drawline_mask.h new file mode 100644 index 000000000..f283ac7fa --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawline_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawline_mask_width 32 +#define drawline_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawpie_curs.h b/vcl/inc/unx/x11_cursors/drawpie_curs.h new file mode 100644 index 000000000..777634e1c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawpie_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawpie_curs_width 32 +#define drawpie_curs_height 32 +#define drawpie_curs_x_hot 7 +#define drawpie_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawpie_mask.h b/vcl/inc/unx/x11_cursors/drawpie_mask.h new file mode 100644 index 000000000..93ac75c2a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawpie_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawpie_mask_width 32 +#define drawpie_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawpolygon_curs.h b/vcl/inc/unx/x11_cursors/drawpolygon_curs.h new file mode 100644 index 000000000..7eebead2a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawpolygon_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawpolygon_curs_width 32 +#define drawpolygon_curs_height 32 +#define drawpolygon_curs_x_hot 7 +#define drawpolygon_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawpolygon_mask.h b/vcl/inc/unx/x11_cursors/drawpolygon_mask.h new file mode 100644 index 000000000..0865ce1f5 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawpolygon_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawpolygon_mask_width 32 +#define drawpolygon_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawrect_curs.h b/vcl/inc/unx/x11_cursors/drawrect_curs.h new file mode 100644 index 000000000..4f98f355f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawrect_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawrect_curs_width 32 +#define drawrect_curs_height 32 +#define drawrect_curs_x_hot 7 +#define drawrect_curs_y_hot 7 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawrect_mask.h b/vcl/inc/unx/x11_cursors/drawrect_mask.h new file mode 100644 index 000000000..b00b06c91 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawrect_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawrect_mask_width 32 +#define drawrect_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawtext_curs.h b/vcl/inc/unx/x11_cursors/drawtext_curs.h new file mode 100644 index 000000000..f530146d7 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawtext_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawtext_curs_width 32 +#define drawtext_curs_height 32 +#define drawtext_curs_x_hot 8 +#define drawtext_curs_y_hot 8 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/drawtext_mask.h b/vcl/inc/unx/x11_cursors/drawtext_mask.h new file mode 100644 index 000000000..75c335bea --- /dev/null +++ b/vcl/inc/unx/x11_cursors/drawtext_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define drawtext_mask_width 32 +#define drawtext_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/fill_curs.h b/vcl/inc/unx/x11_cursors/fill_curs.h new file mode 100644 index 000000000..1cdb63410 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/fill_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define fill_curs_width 32 +#define fill_curs_height 32 +#define fill_curs_x_hot 10 +#define fill_curs_y_hot 22 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/fill_mask.h b/vcl/inc/unx/x11_cursors/fill_mask.h new file mode 100644 index 000000000..df5d4cdeb --- /dev/null +++ b/vcl/inc/unx/x11_cursors/fill_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define fill_mask_width 32 +#define fill_mask_height 32 +#define fill_mask_x_hot 10 +#define fill_mask_y_hot 22 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/hshear_curs.h b/vcl/inc/unx/x11_cursors/hshear_curs.h new file mode 100644 index 000000000..5497f0515 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/hshear_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define hshear_curs_width 32 +#define hshear_curs_height 32 +#define hshear_curs_x_hot 15 +#define hshear_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/hshear_mask.h b/vcl/inc/unx/x11_cursors/hshear_mask.h new file mode 100644 index 000000000..c94277c6a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/hshear_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define hshear_mask_width 32 +#define hshear_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/invert50.h b/vcl/inc/unx/x11_cursors/invert50.h new file mode 100644 index 000000000..cae29c67e --- /dev/null +++ b/vcl/inc/unx/x11_cursors/invert50.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define invert50_width 32 +#define invert50_height 32 +static unsigned char invert50_bits[] = { + 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, +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/linkdata_curs.h b/vcl/inc/unx/x11_cursors/linkdata_curs.h new file mode 100644 index 000000000..8a4e6db38 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/linkdata_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define linkdata_curs_width 32 +#define linkdata_curs_height 32 +#define linkdata_curs_x_hot 1 +#define linkdata_curs_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/linkdata_mask.h b/vcl/inc/unx/x11_cursors/linkdata_mask.h new file mode 100644 index 000000000..a1875a8e0 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/linkdata_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define linkdata_mask_width 32 +#define linkdata_mask_height 32 +#define linkdata_mask_x_hot 1 +#define linkdata_mask_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/linkfile_curs.h b/vcl/inc/unx/x11_cursors/linkfile_curs.h new file mode 100644 index 000000000..571d928d4 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/linkfile_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define linkfile_curs_width 32 +#define linkfile_curs_height 32 +#define linkfile_curs_x_hot 9 +#define linkfile_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/linkfile_mask.h b/vcl/inc/unx/x11_cursors/linkfile_mask.h new file mode 100644 index 000000000..cbef41368 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/linkfile_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define linkfile_mask_width 32 +#define linkfile_mask_height 32 +#define linkfile_mask_x_hot 9 +#define linkfile_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/magnify_curs.h b/vcl/inc/unx/x11_cursors/magnify_curs.h new file mode 100644 index 000000000..4ce3d6e5a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/magnify_curs.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define magnify_curs_width 32 +#define magnify_curs_height 32 +#define magnify_curs_x_hot 12 +#define magnify_curs_y_hot 13 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/magnify_mask.h b/vcl/inc/unx/x11_cursors/magnify_mask.h new file mode 100644 index 000000000..fcc34f886 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/magnify_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define magnify_mask_width 32 +#define magnify_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/mirror_curs.h b/vcl/inc/unx/x11_cursors/mirror_curs.h new file mode 100644 index 000000000..420ff3147 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/mirror_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define mirror_curs_width 32 +#define mirror_curs_height 32 +#define mirror_curs_x_hot 14 +#define mirror_curs_y_hot 12 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/mirror_mask.h b/vcl/inc/unx/x11_cursors/mirror_mask.h new file mode 100644 index 000000000..157accb3c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/mirror_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define mirror_mask_width 32 +#define mirror_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movebezierweight_curs.h b/vcl/inc/unx/x11_cursors/movebezierweight_curs.h new file mode 100644 index 000000000..fdae75127 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movebezierweight_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movebezierweight_curs_width 32 +#define movebezierweight_curs_height 32 +#define movebezierweight_curs_x_hot 0 +#define movebezierweight_curs_y_hot 0 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movebezierweight_mask.h b/vcl/inc/unx/x11_cursors/movebezierweight_mask.h new file mode 100644 index 000000000..08203fe76 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movebezierweight_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movebezierweight_mask_width 32 +#define movebezierweight_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movedata_curs.h b/vcl/inc/unx/x11_cursors/movedata_curs.h new file mode 100644 index 000000000..b253ce70c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movedata_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movedata_curs_width 32 +#define movedata_curs_height 32 +#define movedata_curs_x_hot 1 +#define movedata_curs_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movedata_mask.h b/vcl/inc/unx/x11_cursors/movedata_mask.h new file mode 100644 index 000000000..d317b1556 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movedata_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movedata_mask_width 32 +#define movedata_mask_height 32 +#define movedata_mask_x_hot 1 +#define movedata_mask_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movedlnk_curs.h b/vcl/inc/unx/x11_cursors/movedlnk_curs.h new file mode 100644 index 000000000..1e82e277a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movedlnk_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movedlnk_curs_width 32 +#define movedlnk_curs_height 32 +#define movedlnk_curs_x_hot 1 +#define movedlnk_curs_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movedlnk_mask.h b/vcl/inc/unx/x11_cursors/movedlnk_mask.h new file mode 100644 index 000000000..e56f9714c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movedlnk_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movedlnk_mask_width 32 +#define movedlnk_mask_height 32 +#define movedlnk_mask_x_hot 1 +#define movedlnk_mask_y_hot 1 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movefile_curs.h b/vcl/inc/unx/x11_cursors/movefile_curs.h new file mode 100644 index 000000000..3ffea197f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movefile_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movefile_curs_width 32 +#define movefile_curs_height 32 +#define movefile_curs_x_hot 9 +#define movefile_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movefile_mask.h b/vcl/inc/unx/x11_cursors/movefile_mask.h new file mode 100644 index 000000000..ab74f25d8 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movefile_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movefile_mask_width 32 +#define movefile_mask_height 32 +#define movefile_mask_x_hot 9 +#define movefile_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movefiles_curs.h b/vcl/inc/unx/x11_cursors/movefiles_curs.h new file mode 100644 index 000000000..d5c726a2e --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movefiles_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movefiles_curs_width 32 +#define movefiles_curs_height 32 +#define movefiles_curs_x_hot 8 +#define movefiles_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movefiles_mask.h b/vcl/inc/unx/x11_cursors/movefiles_mask.h new file mode 100644 index 000000000..c1683b333 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movefiles_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movefiles_mask_width 32 +#define movefiles_mask_height 32 +#define movefiles_mask_x_hot 8 +#define movefiles_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/moveflnk_curs.h b/vcl/inc/unx/x11_cursors/moveflnk_curs.h new file mode 100644 index 000000000..02d0c8145 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/moveflnk_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define moveflnk_curs_width 32 +#define moveflnk_curs_height 32 +#define moveflnk_curs_x_hot 9 +#define moveflnk_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/moveflnk_mask.h b/vcl/inc/unx/x11_cursors/moveflnk_mask.h new file mode 100644 index 000000000..189c11443 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/moveflnk_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define moveflnk_mask_width 32 +#define moveflnk_mask_height 32 +#define moveflnk_mask_x_hot 9 +#define moveflnk_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movepoint_curs.h b/vcl/inc/unx/x11_cursors/movepoint_curs.h new file mode 100644 index 000000000..7f85113ce --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movepoint_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movepoint_curs_width 32 +#define movepoint_curs_height 32 +#define movepoint_curs_x_hot 0 +#define movepoint_curs_y_hot 0 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/movepoint_mask.h b/vcl/inc/unx/x11_cursors/movepoint_mask.h new file mode 100644 index 000000000..aa16b5a56 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/movepoint_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define movepoint_mask_width 32 +#define movepoint_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/nodrop_curs.h b/vcl/inc/unx/x11_cursors/nodrop_curs.h new file mode 100644 index 000000000..958257518 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/nodrop_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define nodrop_curs_width 32 +#define nodrop_curs_height 32 +#define nodrop_curs_x_hot 9 +#define nodrop_curs_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/nodrop_mask.h b/vcl/inc/unx/x11_cursors/nodrop_mask.h new file mode 100644 index 000000000..662a30064 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/nodrop_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define nodrop_mask_width 32 +#define nodrop_mask_height 32 +#define nodrop_mask_x_hot 9 +#define nodrop_mask_y_hot 9 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/null_curs.h b/vcl/inc/unx/x11_cursors/null_curs.h new file mode 100644 index 000000000..ebeee4e6f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/null_curs.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define nullcurs_width 4 +#define nullcurs_height 4 +#define nullcurs_x_hot 2 +#define nullcurs_y_hot 2 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/null_mask.h b/vcl/inc/unx/x11_cursors/null_mask.h new file mode 100644 index 000000000..71f08a94a --- /dev/null +++ b/vcl/inc/unx/x11_cursors/null_mask.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define nullmask_width 4 +#define nullmask_height 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotcol_curs.h b/vcl/inc/unx/x11_cursors/pivotcol_curs.h new file mode 100644 index 000000000..a34520ab0 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotcol_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotcol_curs_width 32 +#define pivotcol_curs_height 32 +#define pivotcol_curs_x_hot 7 +#define pivotcol_curs_y_hot 5 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotcol_mask.h b/vcl/inc/unx/x11_cursors/pivotcol_mask.h new file mode 100644 index 000000000..9571a031c --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotcol_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotcol_mask_width 32 +#define pivotcol_mask_height 32 +#define pivotcol_mask_x_hot 7 +#define pivotcol_mask_y_hot 5 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotdel_curs.h b/vcl/inc/unx/x11_cursors/pivotdel_curs.h new file mode 100644 index 000000000..d4547e25f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotdel_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotdel_curs_width 32 +#define pivotdel_curs_height 32 +#define pivotdel_curs_x_hot 9 +#define pivotdel_curs_y_hot 8 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotdel_mask.h b/vcl/inc/unx/x11_cursors/pivotdel_mask.h new file mode 100644 index 000000000..68868aeec --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotdel_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotdel_mask_width 32 +#define pivotdel_mask_height 32 +#define pivotdel_mask_x_hot 9 +#define pivotdel_mask_y_hot 8 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotfld_curs.h b/vcl/inc/unx/x11_cursors/pivotfld_curs.h new file mode 100644 index 000000000..287bc9709 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotfld_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotfld_curs_width 32 +#define pivotfld_curs_height 32 +#define pivotfld_curs_x_hot 8 +#define pivotfld_curs_y_hot 7 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotfld_mask.h b/vcl/inc/unx/x11_cursors/pivotfld_mask.h new file mode 100644 index 000000000..0d5244722 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotfld_mask.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotfld_mask_width 32 +#define pivotfld_mask_height 32 +#define pivotfld_mask_x_hot 8 +#define pivotfld_mask_y_hot 7 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotrow_curs.h b/vcl/inc/unx/x11_cursors/pivotrow_curs.h new file mode 100644 index 000000000..4aec27919 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotrow_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotrow_curs_width 32 +#define pivotrow_curs_height 32 +#define pivotrow_curs_x_hot 8 +#define pivotrow_curs_y_hot 7 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/pivotrow_mask.h b/vcl/inc/unx/x11_cursors/pivotrow_mask.h new file mode 100644 index 000000000..ec9f7f2ba --- /dev/null +++ b/vcl/inc/unx/x11_cursors/pivotrow_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define pivotrow_mask_width 32 +#define pivotrow_mask_height 32 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/rotate_curs.h b/vcl/inc/unx/x11_cursors/rotate_curs.h new file mode 100644 index 000000000..936f9f12b --- /dev/null +++ b/vcl/inc/unx/x11_cursors/rotate_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define rotate_curs_width 32 +#define rotate_curs_height 32 +#define rotate_curs_x_hot 15 +#define rotate_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/rotate_mask.h b/vcl/inc/unx/x11_cursors/rotate_mask.h new file mode 100644 index 000000000..44804f00f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/rotate_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define rotate_mask_width 32 +#define rotate_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/salcursors.h b/vcl/inc/unx/x11_cursors/salcursors.h new file mode 100644 index 000000000..1b8aa6c08 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/salcursors.h @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblsele_curs.h b/vcl/inc/unx/x11_cursors/tblsele_curs.h new file mode 100644 index 000000000..e8ca82dd5 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblsele_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblsele_curs_width 16 +#define tblsele_curs_height 16 +#define tblsele_curs_x_hot 14 +#define tblsele_curs_y_hot 8 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblsele_mask.h b/vcl/inc/unx/x11_cursors/tblsele_mask.h new file mode 100644 index 000000000..6bb306e73 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblsele_mask.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblsele_mask_width 16 +#define tblsele_mask_height 16 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblsels_curs.h b/vcl/inc/unx/x11_cursors/tblsels_curs.h new file mode 100644 index 000000000..54d37ddb0 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblsels_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblsels_curs_width 16 +#define tblsels_curs_height 16 +#define tblsels_curs_x_hot 7 +#define tblsels_curs_y_hot 14 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblsels_mask.h b/vcl/inc/unx/x11_cursors/tblsels_mask.h new file mode 100644 index 000000000..3b6ae7118 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblsels_mask.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblsels_mask_width 16 +#define tblsels_mask_height 16 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselse_curs.h b/vcl/inc/unx/x11_cursors/tblselse_curs.h new file mode 100644 index 000000000..9bedaabcc --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselse_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselse_curs_width 16 +#define tblselse_curs_height 16 +#define tblselse_curs_x_hot 14 +#define tblselse_curs_y_hot 14 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselse_mask.h b/vcl/inc/unx/x11_cursors/tblselse_mask.h new file mode 100644 index 000000000..26cbc3282 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselse_mask.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselse_mask_width 16 +#define tblselse_mask_height 16 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselsw_curs.h b/vcl/inc/unx/x11_cursors/tblselsw_curs.h new file mode 100644 index 000000000..c6f6dedf1 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselsw_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselsw_curs_width 16 +#define tblselsw_curs_height 16 +#define tblselsw_curs_x_hot 1 +#define tblselsw_curs_y_hot 14 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselsw_mask.h b/vcl/inc/unx/x11_cursors/tblselsw_mask.h new file mode 100644 index 000000000..eb9bd3c2d --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselsw_mask.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselsw_mask_width 16 +#define tblselsw_mask_height 16 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselw_curs.h b/vcl/inc/unx/x11_cursors/tblselw_curs.h new file mode 100644 index 000000000..97de23456 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselw_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselw_curs_width 16 +#define tblselw_curs_height 16 +#define tblselw_curs_x_hot 1 +#define tblselw_curs_y_hot 8 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/tblselw_mask.h b/vcl/inc/unx/x11_cursors/tblselw_mask.h new file mode 100644 index 000000000..601fe5396 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/tblselw_mask.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define tblselw_mask_width 16 +#define tblselw_mask_height 16 +static unsigned 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 }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/vertcurs_curs.h b/vcl/inc/unx/x11_cursors/vertcurs_curs.h new file mode 100644 index 000000000..88cc660ba --- /dev/null +++ b/vcl/inc/unx/x11_cursors/vertcurs_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define vertcurs_curs_width 16 +#define vertcurs_curs_height 16 +#define vertcurs_curs_x_hot 8 +#define vertcurs_curs_y_hot 8 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/vertcurs_mask.h b/vcl/inc/unx/x11_cursors/vertcurs_mask.h new file mode 100644 index 000000000..0fbb5d99e --- /dev/null +++ b/vcl/inc/unx/x11_cursors/vertcurs_mask.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define vertcurs_mask_width 16 +#define vertcurs_mask_height 16 +#define vertcurs_mask_x_hot 8 +#define vertcurs_mask_y_hot 8 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/vshear_curs.h b/vcl/inc/unx/x11_cursors/vshear_curs.h new file mode 100644 index 000000000..3e3859cf6 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/vshear_curs.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define vshear_curs_width 32 +#define vshear_curs_height 32 +#define vshear_curs_x_hot 15 +#define vshear_curs_y_hot 15 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/vshear_mask.h b/vcl/inc/unx/x11_cursors/vshear_mask.h new file mode 100644 index 000000000..df7c51a9f --- /dev/null +++ b/vcl/inc/unx/x11_cursors/vshear_mask.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#define vshear_mask_width 32 +#define vshear_mask_height 32 +static unsigned 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}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/wshide_curs.h b/vcl/inc/unx/x11_cursors/wshide_curs.h new file mode 100644 index 000000000..e8fd27230 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/wshide_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define hidewhitespace_curs_width 16 +#define hidewhitespace_curs_height 16 +#define hidewhitespace_curs_x_hot 0 +#define hidewhitespace_curs_y_hot 10 +static unsigned char hidewhitespace_curs_bits[] = { + 0x00, 0x01, 0x00, 0x01, 0xC0, 0x07, 0x80, 0x03, 0x00, 0x01, 0xFF, 0xFF, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x01, + 0x80, 0x03, 0xC0, 0x07, 0x00, 0x01, 0x00, 0x01, }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/wshide_mask.h b/vcl/inc/unx/x11_cursors/wshide_mask.h new file mode 100644 index 000000000..8547baa25 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/wshide_mask.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define hidewhitespace_mask_width 16 +#define hidewhitespace_mask_height 16 +#define hidewhitespace_mask_x_hot 0 +#define hidewhitespace_mask_y_hot 10 +static unsigned char hidewhitespace_mask_bits[] = { + 0x00, 0x01, 0x00, 0x01, 0xC0, 0x07, 0x80, 0x03, 0x00, 0x01, 0xFF, 0xFF, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xFF, 0xFF, 0x00, 0x01, + 0x80, 0x03, 0xC0, 0x07, 0x00, 0x01, 0x00, 0x01, }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/wsshow_curs.h b/vcl/inc/unx/x11_cursors/wsshow_curs.h new file mode 100644 index 000000000..56b705e69 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/wsshow_curs.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define showwhitespace_curs_width 16 +#define showwhitespace_curs_height 16 +#define showwhitespace_curs_x_hot 0 +#define showwhitespace_curs_y_hot 10 +static unsigned char showwhitespace_curs_bits[] = { + 0x00, 0x01, 0x80, 0x03, 0xC0, 0x07, 0x00, 0x01, 0xFF, 0xFF, 0x01, 0x81, + 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0xFF, 0xFF, + 0x00, 0x01, 0xC0, 0x07, 0x80, 0x03, 0x00, 0x01, }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11_cursors/wsshow_mask.h b/vcl/inc/unx/x11_cursors/wsshow_mask.h new file mode 100644 index 000000000..2da7aea99 --- /dev/null +++ b/vcl/inc/unx/x11_cursors/wsshow_mask.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define showwhitespace_mask_width 16 +#define showwhitespace_mask_height 16 +#define showwhitespace_mask_x_hot 0 +#define showwhitespace_mask_y_hot 10 +static unsigned char showwhitespace_mask_bits[] = { + 0x00, 0x01, 0x80, 0x03, 0xC0, 0x07, 0x00, 0x01, 0xFF, 0xFF, 0x01, 0x81, + 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0x01, 0x81, 0xFF, 0xFF, + 0x00, 0x01, 0xC0, 0x07, 0x80, 0x03, 0x00, 0x01, }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcleventlisteners.hxx b/vcl/inc/vcleventlisteners.hxx new file mode 100644 index 000000000..a73349906 --- /dev/null +++ b/vcl/inc/vcleventlisteners.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_VCLEVENTLISTENERS_HXX +#define INCLUDED_VCL_INC_VCLEVENTLISTENERS_HXX + +#include + +class VclEventListeners +{ +public: + void Call( VclSimpleEvent& rEvent ) const; + void addListener( const Link& rListener ); + void removeListener( const Link& rListener ); +private: + std::vector> m_aListeners; +}; + +#endif // INCLUDED_VCL_INC_VCLEVENTLISTENERS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vclpluginapi.h b/vcl/inc/vclpluginapi.h new file mode 100644 index 000000000..589d7244d --- /dev/null +++ b/vcl/inc/vclpluginapi.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_VCLPLUGINAPI_H +#define INCLUDED_VCL_INC_VCLPLUGINAPI_H + +#include +#include + +#if defined VCLPLUG_GEN_IMPLEMENTATION +#define VCLPLUG_GEN_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_GEN_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_GTK_IMPLEMENTATION +#define VCLPLUG_GTK_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_GTK_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_KF5_IMPLEMENTATION +#define VCLPLUG_KF5_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_KF5_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_OSX_IMPLEMENTATION +#define VCLPLUG_OSX_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_OSX_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_QT5_IMPLEMENTATION +#define VCLPLUG_QT5_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_QT5_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_SVP_IMPLEMENTATION +#define VCLPLUG_SVP_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_SVP_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined VCLPLUG_WIN_IMPLEMENTATION +#define VCLPLUG_WIN_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define VCLPLUG_WIN_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#if defined DESKTOP_DETECTOR_IMPLEMENTATION +#define DESKTOP_DETECTOR_PUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define DESKTOP_DETECTOR_PUBLIC SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vclstatuslistener.hxx b/vcl/inc/vclstatuslistener.hxx new file mode 100644 index 000000000..2652befcd --- /dev/null +++ b/vcl/inc/vclstatuslistener.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_VCLSTATUSLISTENER_HXX +#define INCLUDED_VCL_VCLSTATUSLISTENER_HXX + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +template class VclStatusListener final : public cppu::WeakImplHelper < css::frame::XStatusListener> +{ +public: + VclStatusListener(T* widget, const OUString& aCommand); + +private: + VclPtr mWidget; /** The widget on which actions are performed */ + + /** Dispatcher. Need to keep a reference to it as long as this StatusListener exists. */ + css::uno::Reference mxDispatch; + css::util::URL maCommandURL; + css::uno::Reference mxFrame; + +public: + void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override; + + void SAL_CALL disposing(const css::lang::EventObject& /*Source*/) override; + + const css::uno::Reference& getFrame() { return mxFrame; } + + void startListening(); + + void dispose(); +}; + +template +VclStatusListener::VclStatusListener(T* widget, const OUString& aCommand) { + mWidget = widget; + + css::uno::Reference xContext = ::comphelper::getProcessComponentContext(); + css::uno::Reference xDesktop = css::frame::Desktop::create(xContext); + + css::uno::Reference xFrame(xDesktop->getActiveFrame()); + if (!xFrame.is()) + xFrame = xDesktop; + + mxFrame = xFrame; + + maCommandURL.Complete = aCommand; + css::uno::Reference xParser = css::util::URLTransformer::create(xContext); + xParser->parseStrict(maCommandURL); +} + +template +void VclStatusListener::startListening() +{ + if (mxDispatch.is()) + mxDispatch->removeStatusListener(this, maCommandURL); + + css::uno::Reference xDispatchProvider(mxFrame, css::uno::UNO_QUERY); + if (!xDispatchProvider.is()) + return; + + mxDispatch = xDispatchProvider->queryDispatch(maCommandURL, "", 0); + if (mxDispatch.is()) + mxDispatch->addStatusListener(this, maCommandURL); +} + +template +void VclStatusListener::statusChanged(const css::frame::FeatureStateEvent& rEvent) +{ + mWidget->statusChanged(rEvent); +} + +template +void VclStatusListener::disposing(const css::lang::EventObject& /*Source*/) +{ + mxDispatch.clear(); +} + +template +void VclStatusListener::dispose() +{ + if (mxDispatch.is()) { + mxDispatch->removeStatusListener(this, maCommandURL); + mxDispatch.clear(); + } + mxFrame.clear(); + mWidget.clear(); +} + + +#endif // INCLUDED_VCL_VCLSTATUSLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/wall2.hxx b/vcl/inc/wall2.hxx new file mode 100644 index 000000000..401593b3f --- /dev/null +++ b/vcl/inc/wall2.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WALL2_HXX +#define INCLUDED_VCL_INC_WALL2_HXX + +#include + +class ImplWallpaper +{ + friend class Wallpaper; + +private: + std::optional mpRect; + std::unique_ptr mpBitmap; + std::unique_ptr mpGradient; + std::unique_ptr mpCache; + Color maColor; + WallpaperStyle meStyle; + +public: + ImplWallpaper(); + ImplWallpaper( const ImplWallpaper& rImplWallpaper ); + ~ImplWallpaper(); + + bool operator==( const ImplWallpaper& rImplWallpaper ) const = delete; + + friend SvStream& ReadImplWallpaper( SvStream& rIStm, ImplWallpaper& rImplWallpaper ); + friend SvStream& WriteImplWallpaper( SvStream& rOStm, const ImplWallpaper& rImplWallpaper ); +}; + +#endif // INCLUDED_VCL_INC_WALL2_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/watchdog.hxx b/vcl/inc/watchdog.hxx new file mode 100644 index 000000000..9202e432f --- /dev/null +++ b/vcl/inc/watchdog.hxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_WATCHDOG_H +#define INCLUDED_VCL_INC_WATCHDOG_H + +#include +#include +#include +#include + +class WatchdogThread final : private salhelper::Thread +{ + WatchdogThread(); + virtual void execute() override; + +public: + using salhelper::Thread::acquire; + using salhelper::Thread::release; + static void start(); + static void stop(); +}; + +#endif // INCLUDED_VCL_INC_WATCHDOG_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/widgetdraw/WidgetDefinition.hxx b/vcl/inc/widgetdraw/WidgetDefinition.hxx new file mode 100644 index 000000000..cc3eb6606 --- /dev/null +++ b/vcl/inc/widgetdraw/WidgetDefinition.hxx @@ -0,0 +1,298 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_WIDGETDEFINITION_HXX +#define INCLUDED_VCL_INC_WIDGETDEFINITION_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vcl +{ +enum class WidgetDrawActionType +{ + RECTANGLE, + LINE, + IMAGE, + EXTERNAL +}; + +class VCL_DLLPUBLIC WidgetDrawAction +{ +public: + WidgetDrawAction(WidgetDrawActionType aType) + : maType(aType) + { + } + + WidgetDrawActionType maType; +}; + +class VCL_DLLPUBLIC WidgetDrawActionShape : public WidgetDrawAction +{ +public: + WidgetDrawActionShape(WidgetDrawActionType aType) + : WidgetDrawAction(aType) + , mnStrokeWidth(-1) + { + } + + Color maStrokeColor; + Color maFillColor; + sal_Int32 mnStrokeWidth; +}; + +class VCL_DLLPUBLIC WidgetDrawActionRectangle : public WidgetDrawActionShape +{ +public: + sal_Int32 mnRx; + sal_Int32 mnRy; + + float mfX1; + float mfY1; + float mfX2; + float mfY2; + + WidgetDrawActionRectangle() + : WidgetDrawActionShape(WidgetDrawActionType::RECTANGLE) + , mnRx(0) + , mnRy(0) + , mfX1(0.0f) + , mfY1(0.0f) + , mfX2(1.0f) + , mfY2(1.0f) + { + } +}; + +class VCL_DLLPUBLIC WidgetDrawActionLine : public WidgetDrawActionShape +{ +public: + float mfX1; + float mfY1; + float mfX2; + float mfY2; + + WidgetDrawActionLine() + : WidgetDrawActionShape(WidgetDrawActionType::LINE) + , mfX1(0.0) + , mfY1(0.0) + , mfX2(0.0) + , mfY2(0.0) + { + } +}; + +class VCL_DLLPUBLIC WidgetDrawActionImage : public WidgetDrawAction +{ +public: + OUString msSource; + + WidgetDrawActionImage() + : WidgetDrawAction(WidgetDrawActionType::IMAGE) + { + } +}; + +class VCL_DLLPUBLIC WidgetDrawActionExternal : public WidgetDrawAction +{ +public: + OUString msSource; + + WidgetDrawActionExternal() + : WidgetDrawAction(WidgetDrawActionType::EXTERNAL) + { + } +}; + +struct VCL_DLLPUBLIC ControlTypeAndPart +{ + ControlType meType; + ControlPart mePart; + + ControlTypeAndPart(ControlType eType, ControlPart ePart) + : meType(eType) + , mePart(ePart) + { + } + + bool operator==(ControlTypeAndPart const& aOther) const + { + return meType == aOther.meType && mePart == aOther.mePart; + } +}; + +} // end vcl namespace + +namespace std +{ +template <> struct VCL_DLLPUBLIC hash +{ + std::size_t operator()(vcl::ControlTypeAndPart const& rControlTypeAndPart) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, rControlTypeAndPart.meType); + boost::hash_combine(seed, rControlTypeAndPart.mePart); + return seed; + } +}; + +} // end std namespace + +namespace vcl +{ +class WidgetDefinitionState +{ +public: + OString msEnabled; + OString msFocused; + OString msPressed; + OString msRollover; + OString msDefault; + OString msSelected; + OString msButtonValue; + OString msExtra; + + WidgetDefinitionState(OString const& sEnabled, OString const& sFocused, OString const& sPressed, + OString const& sRollover, OString const& sDefault, + OString const& sSelected, OString const& sButtonValue, + OString const& sExtra); + + std::vector> mpWidgetDrawActions; + + void addDrawRectangle(Color aStrokeColor, sal_Int32 nStrokeWidth, Color aFillColor, float fX1, + float fY1, float fX2, float fY2, sal_Int32 nRx, sal_Int32 nRy); + + void addDrawLine(Color aStrokeColor, sal_Int32 nStrokeWidth, float fX1, float fY1, float fX2, + float fY2); + + void addDrawImage(OUString const& sSource); + void addDrawExternal(OUString const& sSource); +}; + +class VCL_DLLPUBLIC WidgetDefinitionPart +{ +public: + sal_Int32 mnWidth; + sal_Int32 mnHeight; + sal_Int32 mnMarginWidth; + sal_Int32 mnMarginHeight; + OString msOrientation; + + std::vector> getStates(ControlType eType, + ControlPart ePart, + ControlState eState, + ImplControlValue const& rValue); + + std::vector> maStates; +}; + +class VCL_DLLPUBLIC WidgetDefinitionSettings +{ +public: + OString msNoActiveTabTextRaise; + OString msCenteredTabs; + OString msListBoxEntryMargin; + OString msDefaultFontSize; + OString msTitleHeight; + OString msFloatTitleHeight; + OString msListBoxPreviewDefaultLogicWidth; + OString msListBoxPreviewDefaultLogicHeight; +}; + +class VCL_DLLPUBLIC WidgetDefinitionStyle +{ +public: + Color maFaceColor; + Color maCheckedColor; + Color maLightColor; + Color maLightBorderColor; + Color maShadowColor; + Color maDarkShadowColor; + Color maDefaultButtonTextColor; + Color maButtonTextColor; + Color maDefaultActionButtonTextColor; + Color maActionButtonTextColor; + Color maFlatButtonTextColor; + Color maDefaultButtonRolloverTextColor; + Color maButtonRolloverTextColor; + Color maDefaultActionButtonRolloverTextColor; + Color maActionButtonRolloverTextColor; + Color maFlatButtonRolloverTextColor; + Color maDefaultButtonPressedRolloverTextColor; + Color maButtonPressedRolloverTextColor; + Color maDefaultActionButtonPressedRolloverTextColor; + Color maActionButtonPressedRolloverTextColor; + Color maFlatButtonPressedRolloverTextColor; + Color maRadioCheckTextColor; + Color maGroupTextColor; + Color maLabelTextColor; + Color maWindowColor; + Color maWindowTextColor; + Color maDialogColor; + Color maDialogTextColor; + Color maWorkspaceColor; + Color maMonoColor; + Color maFieldColor; + Color maFieldTextColor; + Color maFieldRolloverTextColor; + Color maActiveColor; + Color maActiveTextColor; + Color maActiveBorderColor; + Color maDeactiveColor; + Color maDeactiveTextColor; + Color maDeactiveBorderColor; + Color maMenuColor; + Color maMenuBarColor; + Color maMenuBarRolloverColor; + Color maMenuBorderColor; + Color maMenuTextColor; + Color maMenuBarTextColor; + Color maMenuBarRolloverTextColor; + Color maMenuBarHighlightTextColor; + Color maMenuHighlightColor; + Color maMenuHighlightTextColor; + Color maHighlightColor; + Color maHighlightTextColor; + Color maActiveTabColor; + Color maInactiveTabColor; + Color maTabTextColor; + Color maTabRolloverTextColor; + Color maTabHighlightTextColor; + Color maDisableColor; + Color maHelpColor; + Color maHelpTextColor; + Color maLinkColor; + Color maVisitedLinkColor; + Color maToolTextColor; + Color maFontColor; +}; + +class VCL_DLLPUBLIC WidgetDefinition +{ +public: + std::shared_ptr mpStyle; + std::shared_ptr mpSettings; + std::unordered_map> maDefinitions; + std::shared_ptr getDefinition(ControlType eType, ControlPart ePart); +}; + +} // end vcl namespace + +#endif // INCLUDED_VCL_INC_WIDGETDEFINITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/widgetdraw/WidgetDefinitionReader.hxx b/vcl/inc/widgetdraw/WidgetDefinitionReader.hxx new file mode 100644 index 000000000..49ecfac7a --- /dev/null +++ b/vcl/inc/widgetdraw/WidgetDefinitionReader.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_INC_WIDGETDEFINITIONREADER_HXX +#define INCLUDED_VCL_INC_WIDGETDEFINITIONREADER_HXX + +#include +#include +#include +#include +#include + +namespace vcl +{ +class VCL_DLLPUBLIC WidgetDefinitionReader +{ +private: + OUString m_rDefinitionFile; + OUString m_rResourcePath; + + void readDefinition(tools::XmlWalker& rWalker, WidgetDefinition& rWidgetDefinition, + ControlType eType); + + void readPart(tools::XmlWalker& rWalker, std::shared_ptr rpPart); + + void readDrawingDefinition(tools::XmlWalker& rWalker, + const std::shared_ptr& rStates); + +public: + WidgetDefinitionReader(OUString const& rDefinitionFile, OUString const& rResourcePath); + bool read(WidgetDefinition& rWidgetDefinition); +}; + +} // end vcl namespace + +#endif // INCLUDED_VCL_INC_WIDGETDEFINITIONREADER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/DWriteTextRenderer.hxx b/vcl/inc/win/DWriteTextRenderer.hxx new file mode 100644 index 000000000..9011a951d --- /dev/null +++ b/vcl/inc/win/DWriteTextRenderer.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX +#define INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX + +#include +#include +#include + +#include + +enum class D2DTextAntiAliasMode +{ + Default, + Aliased, + AntiAliased, + ClearType, +}; + +class D2DWriteTextOutRenderer : public TextOutRenderer +{ +public: + explicit D2DWriteTextOutRenderer(); + virtual ~D2DWriteTextOutRenderer() override; + + bool operator ()(GenericSalLayout const &rLayout, + SalGraphics &rGraphics, + HDC hDC) override; + + HRESULT BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1)); + + bool BindFont(HDC hDC) /*override*/; + bool ReleaseFont() /*override*/; + + std::vector GetGlyphInkBoxes(uint16_t const * pGid, uint16_t const * pGidEnd) const /*override*/; + ID2D1RenderTarget * GetRenderTarget() const { return mpRT; } + IDWriteFontFace * GetFontFace() const { return mpFontFace; } + float GetEmHeight() const { return mlfEmHeight; } + + HRESULT CreateRenderTarget(); + + bool Ready() const; + + void applyTextAntiAliasMode(); + void changeTextAntiAliasMode(D2DTextAntiAliasMode eMode); + +private: + // This is a singleton object disable copy ctor and assignment operator + D2DWriteTextOutRenderer(const D2DWriteTextOutRenderer &) = delete; + D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; + + bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; + bool performRender(GenericSalLayout const &rLayout, SalGraphics &rGraphics, HDC hDC, bool& bRetry); + + ID2D1Factory * mpD2DFactory; + IDWriteFactory * mpDWriteFactory; + IDWriteGdiInterop * mpGdiInterop; + ID2D1DCRenderTarget * mpRT; + const D2D1_RENDER_TARGET_PROPERTIES mRTProps; + + IDWriteFontFace * mpFontFace; + float mlfEmHeight; + HDC mhDC; + D2DTextAntiAliasMode meTextAntiAliasMode; +}; + +/** + * Sets and unsets the needed DirectWrite transform to support the font's horizontal scaling and + * rotation. + */ +class WinFontTransformGuard +{ +public: + WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, float fHScale, const GenericSalLayout& rLayout, const D2D1_POINT_2F& rBaseline); + ~WinFontTransformGuard(); + +private: + ID2D1RenderTarget* mpRenderTarget; + D2D1::Matrix3x2F maTransform; +}; + +#endif // INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salbmp.h b/vcl/inc/win/salbmp.h new file mode 100644 index 000000000..d6acd14e8 --- /dev/null +++ b/vcl/inc/win/salbmp.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALBMP_H +#define INCLUDED_VCL_INC_WIN_SALBMP_H + +#include +#include +#include +#include +#include + + +struct BitmapBuffer; +class BitmapColor; +class BitmapPalette; +class SalGraphics; +namespace Gdiplus { class Bitmap; } + +class WinSalBitmap final: public SalBitmap, public basegfx::SystemDependentDataHolder +{ +private: + Size maSize; + HGLOBAL mhDIB; + HBITMAP mhDDB; + + sal_uInt16 mnBitCount; + + Gdiplus::Bitmap* ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlphaSource); + Gdiplus::Bitmap* ImplCreateGdiPlusBitmap(); + +public: + + HGLOBAL ImplGethDIB() const { return mhDIB; } + HBITMAP ImplGethDDB() const { return mhDDB; } + + std::shared_ptr< Gdiplus::Bitmap > ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource = nullptr) const; + + static HGLOBAL ImplCreateDIB( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ); + static HANDLE ImplCopyDIBOrDDB( HANDLE hHdl, bool bDIB ); + static sal_uInt16 ImplGetDIBColorCount( HGLOBAL hDIB ); + static void ImplDecodeRLEBuffer( const BYTE* pSrcBuf, BYTE* pDstBuf, + const Size& rSizePixel, bool bRLE4 ); + +public: + + WinSalBitmap(); + virtual ~WinSalBitmap() override; + +public: + + bool Create( HANDLE hBitmap, bool bDIB, bool bCopyHandle ); + virtual bool Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) override; + virtual bool Create( const SalBitmap& rSalBmpImpl ) override; + virtual bool Create( const SalBitmap& rSalBmpImpl, SalGraphics* pGraphics ) override; + virtual bool Create( const SalBitmap& rSalBmpImpl, sal_uInt16 nNewBitCount ) override; + virtual bool Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& rBitmapCanvas, + Size& rSize, + bool bMask = false ) override; + + virtual void Destroy() override; + + virtual Size GetSize() const override { return maSize; } + virtual sal_uInt16 GetBitCount() const override { return mnBitCount; } + + virtual BitmapBuffer* AcquireBuffer( BitmapAccessMode nMode ) override; + virtual void ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) override; + virtual bool GetSystemData( BitmapSystemData& rData ) override; + + virtual bool ScalingSupported() const override; + virtual bool Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) override; + virtual bool Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) override; + + // exclusive management op's for SystemDependentData at WinSalBitmap + template + std::shared_ptr getSystemDependentData() const + { + return std::static_pointer_cast(basegfx::SystemDependentDataHolder::getSystemDependentData(typeid(T).hash_code())); + } + + template + std::shared_ptr addOrReplaceSystemDependentData(basegfx::SystemDependentDataManager& manager, Args&&... args) const + { + std::shared_ptr r = std::make_shared(manager, std::forward(args)...); + + // tdf#129845 only add to buffer if a relevant buffer time is estimated + if(r->calculateCombinedHoldCyclesInSeconds() > 0) + { + basegfx::SystemDependentData_SharedPtr r2(r); + const_cast< WinSalBitmap* >(this)->basegfx::SystemDependentDataHolder::addOrReplaceSystemDependentData(r2); + } + + return r; + } +}; + +#endif // INCLUDED_VCL_INC_WIN_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/saldata.hxx b/vcl/inc/win/saldata.hxx new file mode 100644 index 000000000..eadc7ade8 --- /dev/null +++ b/vcl/inc/win/saldata.hxx @@ -0,0 +1,305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALDATA_HXX +#define INCLUDED_VCL_INC_WIN_SALDATA_HXX + +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +class AutoTimer; +class WinSalInstance; +class WinSalObject; +class WinSalFrame; +class WinSalVirtualDevice; +class WinSalPrinter; +namespace vcl { class Font; } +struct GlobalWinGlyphCache; +struct HDCCache; +struct TempFontItem; +class TextOutRenderer; +class OpenGLControlsCache; +#if HAVE_FEATURE_SKIA +class SkiaControlsCache; +#endif + +#define MAX_STOCKPEN 4 +#define MAX_STOCKBRUSH 4 +#define SAL_CLIPRECT_COUNT 16 + +struct SalIcon +{ + int nId; + HICON hIcon; + HICON hSmallIcon; + SalIcon *pNext; +}; + +class SalData +{ +public: + SalData(); + ~SalData(); + + // native widget framework + static void initNWF(); + static void deInitNWF(); + + // fill maVKMap; + void initKeyCodeMap(); + + // checks if the menuhandle was created by VCL + bool IsKnownMenuHandle( HMENU hMenu ); + + bool mbResourcesAlreadyFreed; + +public: + HINSTANCE mhInst; // default 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 + 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* mpInstance; + 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]; + sal_uInt16 mnStockPenCount; // count of static pens + sal_uInt16 mnStockBrushCount; // count of static brushes + WPARAM mnSalObjWantKeyEvt; // KeyEvent that should be processed by SalObj-Hook + BYTE mnCacheDCInUse; // count of CacheDC in use + bool mbObjClassInit; // is SALOBJECTCLASS initialised + bool mbInPalChange; // is in WM_QUERYNEWPALETTE + DWORD mnAppThreadId; // Id from Application-Thread + BOOL mbScrSvrEnabled; // ScreenSaver enabled + SalIcon* mpFirstIcon; // icon cache, points to first icon, NULL if none + TempFontItem* mpSharedTempFontItem; // LibreOffice shared fonts + TempFontItem* mpOtherTempFontItem; // other temporary fonts (embedded?) + bool mbThemeChanged; // true if visual theme was changed: throw away theme handles + bool mbThemeMenuSupport; + + // 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,sal_uInt16 > maVKMap; // map some dynamic VK_* entries + + std::unique_ptr m_pD2DWriteTextOutRenderer; + // tdf#107205 need 2 instances because D2DWrite can't rotate text + std::unique_ptr m_pExTextOutRenderer; + std::unique_ptr m_pGlobalWinGlyphCache; + std::unique_ptr m_pOpenGLControlsCache; +#if HAVE_FEATURE_SKIA + std::unique_ptr m_pSkiaControlsCache; +#endif +}; + +inline void SetSalData( SalData* pData ) { ImplGetSVData()->mpSalData = pData; } +inline SalData* GetSalData() { return ImplGetSVData()->mpSalData; } + +struct SalShlData +{ + HINSTANCE mhInst; // Instance of SAL-DLL + UINT mnWheelScrollLines; // WheelScrollLines + UINT mnWheelScrollChars; // WheelScrollChars +}; + +extern SalShlData aSalShlData; + +#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( sal_uLong nID, HBITMAP hBmp = nullptr ); +void ImplReleaseCachedDC( sal_uLong nID ); + +void ImplReleaseTempFonts(SalData&, bool bAll); + +HCURSOR ImplLoadSalCursor( int nId ); +HBITMAP ImplLoadSalBitmap( int nId ); +bool ImplLoadSalIcon( int nId, HICON& rIcon, HICON& rSmallIcon ); + +void ImplInitSalGDI(); +void ImplFreeSalGDI(); + +void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount = 1 ); +bool ImplSalYieldMutexTryToAcquire(); +void ImplSalYieldMutexRelease(); + +LRESULT CALLBACK SalFrameWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); + +void SalTestMouseLeave(); + +bool ImplHandleSalObjKeyMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam ); +bool ImplHandleSalObjSysCharMsg( HWND hWnd, WPARAM wParam, LPARAM lParam ); +bool ImplHandleGlobalMsg( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT& rlResult ); + +WinSalObject* ImplFindSalObject( HWND hWndChild ); +bool ImplSalPreDispatchMsg( const MSG* pMsg ); +void ImplSalPostDispatchMsg( const MSG* pMsg ); + +void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, vcl::Font& rFont ); + +rtl_TextEncoding ImplSalGetSystemEncoding(); +OUString ImplSalGetUniString(const char* pStr, sal_Int32 nLen = -1); +int ImplSalWICompareAscii( const wchar_t* pStr1, const char* pStr2 ); + +#define SAL_FRAME_WNDEXTRA sizeof( DWORD ) +#define SAL_FRAME_THIS GWLP_USERDATA +#define SAL_FRAME_CLASSNAMEW L"SALFRAME" +#define SAL_SUBFRAME_CLASSNAMEW L"SALSUBFRAME" +#define SAL_TMPSUBFRAME_CLASSNAMEW L"SALTMPSUBFRAME" +#define SAL_OBJECT_WNDEXTRA sizeof( DWORD ) +#define SAL_OBJECT_THIS GWLP_USERDATA +#define SAL_OBJECT_CLASSNAMEW L"SALOBJECT" +#define SAL_OBJECT_CHILDCLASSNAMEW L"SALOBJECTCHILD" +#define SAL_COM_CLASSNAMEW L"SALCOMWND" + +#define SAL_MOUSELEAVE_TIMEOUT 300 + +// wParam == bWait; lParam == 0 +#define SAL_MSG_THREADYIELD (WM_USER+111) +// 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_GETCACHEDDC (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 relative to upper left of screen +#define SAL_MSG_MOUSELEAVE (WM_USER+131) +// NULL-Message, should not be processed +#define SAL_MSG_DUMMY (WM_USER+132) +// Used for SETFOCUS and KILLFOCUS +// 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) + +// SysChild-ToTop; wParam = 0; lParam = 0 +#define SALOBJ_MSG_TOTOP (WM_USER+160) +// Used for SETFOCUS and KILLFOCUS +// POSTFOCUS-Message; wParam == bFocus; lParam == 0 +#define SALOBJ_MSG_POSTFOCUS (WM_USER+161) + +// Call the Timer's callback from the main thread +// wParam = 1 == run when yield is idle instead of direct +#define SAL_MSG_TIMER_CALLBACK (WM_USER+162) +// Stop the timer from the main thread; wParam = 0, lParam = 0 +#define SAL_MSG_STOPTIMER (WM_USER+163) +// Start a real timer while GUI is blocked by native dialog +#define SAL_MSG_FORCE_REAL_TIMER (WM_USER+164) + +inline void SetWindowPtr( HWND hWnd, WinSalFrame* pThis ) +{ + SetWindowLongPtrW( hWnd, SAL_FRAME_THIS, reinterpret_cast(pThis) ); +} + +inline WinSalFrame* GetWindowPtr( HWND hWnd ) +{ + return reinterpret_cast(GetWindowLongPtrW( hWnd, SAL_FRAME_THIS )); +} + +inline void SetSalObjWindowPtr( HWND hWnd, WinSalObject* pThis ) +{ + SetWindowLongPtrW( hWnd, SAL_OBJECT_THIS, reinterpret_cast(pThis) ); +} + +inline WinSalObject* GetSalObjWindowPtr( HWND hWnd ) +{ + return reinterpret_cast(GetWindowLongPtrW( hWnd, SAL_OBJECT_THIS )); +} + +#endif // INCLUDED_VCL_INC_WIN_SALDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salframe.h b/vcl/inc/win/salframe.h new file mode 100644 index 000000000..f0c758806 --- /dev/null +++ b/vcl/inc/win/salframe.h @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALFRAME_H +#define INCLUDED_VCL_INC_WIN_SALFRAME_H + +#include +#include +#include + +class WinSalGraphics; + + +class WinSalFrame final: public SalFrame +{ +public: + HWND mhWnd; // Window handle + HCURSOR mhCursor; // cursor handle + HIMC mhDefIMEContext; // default IME-Context + WinSalGraphics* mpLocalGraphics; // current main thread frame graphics + WinSalGraphics* mpThreadGraphics; // current frame graphics for other threads (DCX_CACHE) + 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 + bool mbFullScreenCaption; // WS_CAPTION reset in full screen mode. + UINT mnInputLang; // current Input Language + UINT mnInputCodePage; // current Input CodePage + SalFrameStyleFlags 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 a window without an icon + bool mbFloatWin; // is a FloatingWindow + bool mbFullScreen; // TRUE: in full screen mode + bool mbPresentation; // TRUE: Presentation Mode running + bool mbInShow; // inside a show call + bool mbRestoreMaximize; // Restore-Maximize + bool mbInMoveMsg; // Move-Message is being processed + bool mbInSizeMsg; // Size-Message is being processed + bool mbFullScreenToolWin; // WS_EX_TOOLWINDOW reset in FullScreenMode + bool mbDefPos; // default-position + bool mbOverwriteState; // TRUE: possible to change WindowState + bool mbIME; // TRUE: We are in IME Mode + bool mbHandleIME; // TRUE: We are handling the IME-Messages + bool mbSpezIME; // TRUE: special IME + bool mbAtCursorIME; // TRUE: We are only handling some IME-Messages + bool mbCandidateMode; // TRUE: We are in Candidate-Mode + 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 + bool mbPropertiesStored; // has values stored in the window property store + + void updateScreenNumber(); + +private: + void ImplSetParentFrame( HWND hNewParentWnd, bool bAsChild ); + bool InitFrameGraphicsDC( WinSalGraphics *pGraphics, HDC hDC, HWND hWnd ); + bool ReleaseFrameGraphicsDC( WinSalGraphics* pGraphics ); + +public: + WinSalFrame(); + virtual ~WinSalFrame() override; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool PostEvent(std::unique_ptr pData) override; + virtual void SetTitle( const OUString& rTitle ) override; + virtual void SetIcon( sal_uInt16 nIcon ) override; + virtual void SetMenu( SalMenu* pSalMenu ) override; + virtual void DrawMenuBar() override; + virtual void SetExtendedFrameStyle( SalExtStyle nExtStyle ) override; + virtual void Show( bool bVisible, bool bNoActivate = false ) override; + virtual void SetMinClientSize( long nWidth, long nHeight ) override; + virtual void SetMaxClientSize( long nWidth, long nHeight ) override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags ) override; + virtual void GetClientSize( long& rWidth, long& rHeight ) override; + virtual void GetWorkArea( tools::Rectangle& rRect ) override; + virtual SalFrame* GetParent() const override; + virtual void SetWindowState( const SalFrameState* pState ) override; + virtual bool GetWindowState( SalFrameState* pState ) override; + virtual void ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) override; + virtual void StartPresentation( bool bStart ) override; + virtual void SetAlwaysOnTop( bool bOnTop ) override; + virtual void ToTop( SalFrameToTop nFlags ) override; + virtual void SetPointer( PointerStyle ePointerStyle ) override; + virtual void CaptureMouse( bool bMouse ) override; + virtual void SetPointerPos( long nX, long nY ) override; + using SalFrame::Flush; + virtual void Flush() override; + virtual void SetInputContext( SalInputContext* pContext ) override; + virtual void EndExtTextInput( EndExtTextInputFlags nFlags ) override; + virtual OUString GetKeyName( sal_uInt16 nKeyCode ) override; + virtual bool MapUnicodeToKeyCode( sal_Unicode aUnicode, LanguageType aLangType, vcl::KeyCode& rKeyCode ) override; + virtual LanguageType GetInputLanguage() override; + virtual void UpdateSettings( AllSettings& rSettings ) override; + virtual void Beep() override; + virtual const SystemEnvData* GetSystemData() const override; + virtual SalPointerState GetPointerState() override; + virtual KeyIndicatorState GetIndicatorState() override; + virtual void SimulateKeyPress( sal_uInt16 nKeyCode ) override; + virtual void SetParent( SalFrame* pNewParent ) override; + virtual bool SetPluginParent( SystemParentData* pNewParent ) override; + virtual void SetScreenNumber( unsigned int ) override; + virtual void SetApplicationID( const OUString &rApplicationID ) override; + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) override; + virtual void EndSetClipRegion() override; +}; + +void ImplSalGetWorkArea( HWND hWnd, RECT *pRect, const RECT *pParentRect ); + +// get foreign key names +namespace vcl_sal { + OUString getKeysReplacementName( + OUString const & pLang, + LONG nSymbol ); +} + +#endif // INCLUDED_VCL_INC_WIN_SALFRAME_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h new file mode 100644 index 000000000..83c6b6f2d --- /dev/null +++ b/vcl/inc/win/salgdi.h @@ -0,0 +1,429 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALGDI_H +#define INCLUDED_VCL_INC_WIN_SALGDI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifndef INCLUDED_PRE_POST_WIN_H +#define INCLUDED_PRE_POST_WIN_H +# include +# include +#endif + +#include +#include + +class FontSelectPattern; +class WinFontInstance; +class ImplFontAttrCache; +class PhysicalFontCollection; +class SalGraphicsImpl; +class WinSalGraphicsImplBase; +class ImplFontMetricData; + +#define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000) +#define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff) + +// win32 specific physically available font face +class WinFontFace : public PhysicalFontFace +{ +public: + explicit WinFontFace( const FontAttributes&, + BYTE eWinCharSet, + BYTE nPitchAndFamily ); + virtual ~WinFontFace() override; + + virtual rtl::Reference CreateFontInstance( const FontSelectPattern& ) const override; + virtual sal_IntPtr GetFontId() const override; + void SetFontId( sal_IntPtr nId ) { mnId = nId; } + void UpdateFromHDC( HDC ) const; + + bool HasChar( sal_uInt32 cChar ) const; + + BYTE GetCharSet() const { return meWinCharSet; } + BYTE GetPitchAndFamily() const { return mnPitchAndFamily; } + + FontCharMapRef GetFontCharMap() const; + bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const; + +private: + sal_IntPtr mnId; + + // some members that are initialized lazily when the font gets selected into a HDC + mutable bool mbFontCapabilitiesRead; + mutable FontCharMapRef mxUnicodeMap; + mutable vcl::FontCapabilities maFontCapabilities; + + BYTE meWinCharSet; + BYTE mnPitchAndFamily; + bool mbAliasSymbolsHigh; + bool mbAliasSymbolsLow; + + void ReadCmapTable( HDC ) const; + void GetFontCapabilities( HDC hDC ) const; +}; + +/** Class that creates (and destroys) a compatible Device Context. + +This is to be used for GDI drawing into a DIB that we later use for a different +drawing method, such as a texture for OpenGL drawing or surface for Skia drawing. +*/ +class CompatibleDC +{ +protected: + /// The compatible DC that we create for our purposes. + HDC mhCompatibleDC; + + /// DIBSection that we use for the GDI drawing, and later obtain. + HBITMAP mhBitmap; + + /// Return the previous bitmap to undo the SelectObject. + HBITMAP mhOrigBitmap; + + /// DIBSection data. + sal_uInt32 *mpData; + + /// Mapping between the GDI position and OpenGL, to use for OpenGL drawing. + SalTwoRect maRects; + + /// The SalGraphicsImpl where we will draw. If null, we ignore the drawing, it means it happened directly to the DC... + WinSalGraphicsImplBase *mpImpl; + + // If 'disable' is true, this class is a simple wrapper for drawing directly. Subclasses should use true. + CompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height, bool disable=true); + +public: + static std::unique_ptr< CompatibleDC > create(SalGraphics &rGraphics, int x, int y, int width, int height); + + virtual ~CompatibleDC(); + + HDC getCompatibleHDC() { return mhCompatibleDC; } + + SalTwoRect getTwoRect() const { return maRects; } + + long getBitmapWidth() const { return maRects.mnSrcWidth; } + long getBitmapHeight() const { return maRects.mnSrcHeight; } + + /// Reset the DC with the defined color. + void fill(sal_uInt32 color); + + /// Base texture class (OpenGL and Skia will provide their implementations). + struct Texture; + + /// Obtain the texture in format for WinSalGraphicsImplBase::DrawTextMask(). + virtual std::unique_ptr getAsMaskTexture() const { abort(); }; +}; + +struct CompatibleDC::Texture +{ + virtual ~Texture() {}; + virtual bool isValid() const = 0; + virtual int GetWidth() const = 0; + virtual int GetHeight() const = 0; +}; + +class WinSalGraphics : public SalGraphics +{ + friend class WinSalGraphicsImpl; + friend class WinOpenGLSalGraphicsImpl; + friend class ScopedFont; + +protected: + std::unique_ptr mpImpl; + +private: + HDC mhLocalDC; // HDC + bool mbPrinter : 1; // is Printer + bool mbVirDev : 1; // is VirDev + bool mbWindow : 1; // is Window + bool mbScreen : 1; // is Screen compatible + HWND mhWnd; // Window-Handle, when Window-Graphics + + rtl::Reference + mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance + HRGN mhRegion; // vcl::Region Handle + HPEN mhDefPen; // DefaultPen + HBRUSH mhDefBrush; // DefaultBrush + HFONT mhDefFont; // DefaultFont + HPALETTE mhDefPal; // DefaultPalette + COLORREF mnTextColor; // TextColor + RGNDATA* mpClipRgnData; // ClipRegion-Data + RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data + int mnPenWidth; // line width + + bool CacheGlyphs(const GenericSalLayout& rLayout); + bool DrawCachedGlyphs(const GenericSalLayout& rLayout); + +public: + HFONT ImplDoSetFont(FontSelectPattern const & i_rFont, const PhysicalFontFace * i_pFontFace, HFONT& o_rOldFont); + + HDC getHDC() const { return mhLocalDC; } + void setHDC(HDC aNew) { mhLocalDC = aNew; } + + HPALETTE getDefPal() const; + void setDefPal(HPALETTE hDefPal); + + HRGN getRegion() const; + + void InitGraphics(); + void DeInitGraphics(); + + enum Type + { + PRINTER, + VIRTUAL_DEVICE, + WINDOW, + SCREEN + }; + +public: + + HWND gethWnd(); + + +public: + explicit WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd, + SalGeometryProvider *pProvider); + virtual ~WinSalGraphics() override; + + SalGraphicsImpl* GetImpl() const override; + bool isPrinter() const; + bool isVirtualDevice() const; + bool isWindow() const; + bool isScreen() const; + + void setHWND(HWND hWnd); + +protected: + virtual bool setClipRegion( const vcl::Region& ) override; + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) override; + virtual void drawPixel( long nX, long nY, Color nColor ) override; + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) override; + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) override; + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override; + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override; + virtual bool drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon&, + double fTransparency) override; + virtual bool drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon&, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin, + css::drawing::LineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) override; + virtual bool drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; + virtual bool drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override; + virtual bool drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry ) override; + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) override { return false; }; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool bWindowInvalidate ) override; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) override; + virtual void drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) override; + virtual void drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) override; + + virtual std::shared_ptr getBitmap( long nX, long nY, long nWidth, long nHeight ) override; + virtual Color getPixel( long nX, long nY ) override; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) override; + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) override; + + virtual bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uInt32 nSize ) override; + + // native widget rendering methods that require mirroring +protected: + virtual bool isNativeControlSupported( ControlType nType, ControlPart nPart ) override; + virtual bool hitTestNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + const Point& aPos, bool& rIsInside ) override; + virtual bool drawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const OUString& aCaption, const Color& rBackgroundColor ) override; + virtual bool getNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, + const ImplControlValue& aValue, const OUString& aCaption, + tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion ) override; + +public: + virtual bool blendBitmap( const SalTwoRect&, + const SalBitmap& rBitmap ) override; + + virtual bool blendAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap ) override; + + virtual bool drawAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) override; + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) override; + virtual bool drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) override; + +private: + // local helpers + + void DrawTextLayout(const GenericSalLayout&, HDC, bool bUseDWrite); + +public: + // public SalGraphics methods, the interface to the independent vcl part + + // get device resolution + virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) override; + // get the depth of the device + virtual sal_uInt16 GetBitCount() const override; + // get the width of the device + virtual long GetGraphicsWidth() const override; + + // set the clip region to empty + virtual void ResetClipRegion() override; + + // set the line color to transparent (= don't draw lines) + virtual void SetLineColor() override; + // set the line color to a specific color + virtual void SetLineColor( Color nColor ) override; + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() override; + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( Color nColor ) override; + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool ) override; + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) override; + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) override; + // set the text color to a specific color + virtual void SetTextColor( Color nColor ) override; + // set the font + virtual void SetFont( LogicalFontInstance*, int nFallbackLevel ) override; + // get the current font's metrics + virtual void GetFontMetric( ImplFontMetricDataRef&, int nFallbackLevel ) override; + // get the repertoire of the current font + virtual FontCharMapRef GetFontCharMap() const override; + // get the layout capabilities of the current font + virtual bool GetFontCapabilities(vcl::FontCapabilities &rGetFontCapabilities) const override; + // graphics must fill supplied font list + virtual void GetDevFontList( PhysicalFontCollection* ) override; + // graphics must drop any cached font info + virtual void ClearDevFontCache() override; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) override; + // 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 successful + // parameters: rToFile: contains an 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 corresponding 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 OUString& rToFile, + const PhysicalFontFace*, + const sal_GlyphId* pGlyphIDs, + const sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo // out parameter + ) override; + + // 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 + // pDataLen: out parameter, contains the byte length of the returned buffer + virtual const void* GetEmbedFontData(const PhysicalFontFace*, long* pDataLen) override; + // frees the font data again + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) override; + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + std::vector< sal_Int32 >& rWidths, + Ucs2UIntMap& rUnicodeEnc ) override; + + virtual std::unique_ptr + GetTextLayout(int nFallbackLevel) override; + virtual void DrawTextLayout( const GenericSalLayout& ) override; + + virtual bool supportsOperation( OutDevSupportType ) const override; + + virtual SystemGraphicsData GetGraphicsData() const override; + + /// Update settings based on the platform values + static void updateSettingsNative( AllSettings& rSettings ); +}; + +// Init/Deinit Graphics +void ImplUpdateSysColorEntries(); +int ImplIsSysColorEntry( Color nColor ); +void ImplGetLogFontFromFontSelect( HDC, const FontSelectPattern&, + const PhysicalFontFace*, LOGFONTW& ); + +#define MAX_64KSALPOINTS ((((sal_uInt16)0xFFFF)-8)/sizeof(POINTS)) + +// called extremely often from just one spot => inline +inline bool WinFontFace::HasChar( sal_uInt32 cChar ) const +{ + if( mxUnicodeMap->HasChar( cChar ) ) + return true; + // second chance to allow symbol aliasing + if( mbAliasSymbolsLow && ((cChar-0xF000) <= 0xFF) ) + cChar -= 0xF000; + else if( mbAliasSymbolsHigh && (cChar <= 0xFF) ) + cChar += 0xF000; + else + return false; + return mxUnicodeMap->HasChar( cChar ); +} + +#endif // INCLUDED_VCL_INC_WIN_SALGDI_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salids.hrc b/vcl/inc/win/salids.hrc new file mode 100644 index 000000000..092a24b52 --- /dev/null +++ b/vcl/inc/win/salids.hrc @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALIDS_HRC +#define INCLUDED_VCL_INC_WIN_SALIDS_HRC + +// Cursor +#define SAL_RESID_POINTER_NULL 10000 +#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_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_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_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_HIDEWHITESPACE 10079 +#define SAL_RESID_POINTER_SHOWWHITESPACE 10080 + +#define SAL_RESID_BITMAP_50 11000 + +#define SAL_RESID_ICON_DEFAULT 1 + +#endif // INCLUDED_VCL_INC_WIN_SALIDS_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salinst.h b/vcl/inc/win/salinst.h new file mode 100644 index 000000000..c06e51c84 --- /dev/null +++ b/vcl/inc/win/salinst.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALINST_H +#define INCLUDED_VCL_INC_WIN_SALINST_H + +#include + +#include + +#include + +class SalYieldMutex; + +class WinSalInstance : public SalInstance +{ +public: + /// Instance Handle + HINSTANCE mhInst; + /// invisible Window so non-main threads can SendMessage() the main thread + HWND mhComWnd; + + osl::Condition maWaitingYieldCond; + unsigned m_nNoYieldLock; + +public: + WinSalInstance(); + virtual ~WinSalInstance() override; + + virtual SalFrame* CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) override; + virtual SalFrame* CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) override; + virtual void DestroyFrame( SalFrame* pFrame ) override; + virtual SalObject* CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow ) override; + virtual void DestroyObject( SalObject* pObject ) override; + virtual std::unique_ptr + CreateVirtualDevice( SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData *pData = nullptr ) override; + virtual SalInfoPrinter* CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) override; + virtual void DestroyInfoPrinter( SalInfoPrinter* pPrinter ) override; + virtual std::unique_ptr CreatePrinter( SalInfoPrinter* pInfoPrinter ) override; + virtual void GetPrinterQueueInfo( ImplPrnQueueList* pList ) override; + virtual void GetPrinterQueueState( SalPrinterQueueInfo* pInfo ) override; + virtual OUString GetDefaultPrinter() override; + virtual SalTimer* CreateSalTimer() override; + virtual SalSystem* CreateSalSystem() override; + virtual std::shared_ptr CreateSalBitmap() override; + virtual bool IsMainThread() const override; + + virtual bool DoYield(bool bWait, bool bHandleAllCurrentEvents) override; + virtual bool AnyInput( VclInputFlags nType ) override; + virtual std::unique_ptr CreateMenu( bool bMenuBar, Menu* ) override; + virtual std::unique_ptr CreateMenuItem( const SalItemParams & rItemData ) override; + virtual OpenGLContext* CreateOpenGLContext() override; + virtual OUString GetConnectionIdentifier() override; + virtual void AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType, const OUString& rDocumentService) override; + + virtual OUString getOSVersion() override; + virtual std::shared_ptr GetBackendCapabilities() override; + + static int WorkaroundExceptionHandlingInUSER32Lib(int nExcept, LPEXCEPTION_POINTERS pExceptionInfo); +}; + +SalFrame* ImplSalCreateFrame( WinSalInstance* pInst, HWND hWndParent, SalFrameStyleFlags nSalFrameStyle ); +SalObject* ImplSalCreateObject( WinSalInstance* pInst, WinSalFrame* pParent ); +HWND ImplSalReCreateHWND( HWND hWndParent, HWND oldhWnd, bool bAsChild ); + +#endif // INCLUDED_VCL_INC_WIN_SALINST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salmenu.h b/vcl/inc/win/salmenu.h new file mode 100644 index 000000000..7058d9c82 --- /dev/null +++ b/vcl/inc/win/salmenu.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALMENU_H +#define INCLUDED_VCL_INC_WIN_SALMENU_H + +#include +#include + +class WinSalMenu : public SalMenu +{ +public: + WinSalMenu(); + virtual ~WinSalMenu() override; + virtual bool VisibleMenuBar() override; // 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 ) override; + virtual void RemoveItem( unsigned nPos ) override; + virtual void SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos ) override; + virtual void SetFrame( const SalFrame* pFrame ) override; + virtual void CheckItem( unsigned nPos, bool bCheck ) override; + virtual void EnableItem( unsigned nPos, bool bEnable ) override; + virtual void SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const OUString& rText ) override; + virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage ) override; + virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const vcl::KeyCode& rKeyCode, const OUString& rKeyName ) override; + virtual void GetSystemMenuData( SystemMenuData* pData ) override; + + 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() override; + + MENUITEMINFOW mInfo; + void* mpMenu; // pointer to corresponding VCL menu + OUString mText; // the item text + OUString mAccelText; // the accelerator string + Bitmap maBitmap; // item image + int mnId; // item id + WinSalMenu* mpSalMenu; // the menu where this item is inserted +}; + +#endif // INCLUDED_VCL_INC_WIN_SALMENU_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salobj.h b/vcl/inc/win/salobj.h new file mode 100644 index 000000000..465c9ec77 --- /dev/null +++ b/vcl/inc/win/salobj.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALOBJ_H +#define INCLUDED_VCL_INC_WIN_SALOBJ_H + +#include + + +class WinSalObject : public SalObject +{ +public: + HWND mhWnd; // Window handle + HWND mhWndChild; // Child Window handle + HWND mhLastFocusWnd; // Child-Window, which had the last focus + SystemEnvData maSysData; // SystemEnvData + RGNDATA* mpClipRgnData; // ClipRegion-Data + RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data + RECT* mpNextClipRect; // next ClipRegion-Rect + bool mbFirstClipRect; // Flag for first cliprect to insert + WinSalObject* mpNextObject; // pointer to next object + + WinSalObject(); + virtual ~WinSalObject() override; + + virtual void ResetClipRegion() override; + virtual void BeginSetClipRegion( sal_uInt32 nRects ) override; + virtual void UnionClipRegion( long nX, long nY, long nWidth, long nHeight) override; + virtual void EndSetClipRegion() override; + virtual void SetPosSize( long nX, long nY, long nWidth, long nHeight ) override; + virtual void Show( bool bVisible ) override; + virtual void Enable( bool bEnable ) override; + virtual void GrabFocus() override; + virtual const SystemEnvData* GetSystemData() const override; +}; + +#endif // INCLUDED_VCL_INC_WIN_SALOBJ_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salprn.h b/vcl/inc/win/salprn.h new file mode 100644 index 000000000..c0c6e7fb7 --- /dev/null +++ b/vcl/inc/win/salprn.h @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALPRN_H +#define INCLUDED_VCL_INC_WIN_SALPRN_H + +#include + + +// WNT3 +#define SAL_DRIVERDATA_SYSSIGN ((sal_uIntPtr)0x574E5433) + +#pragma pack( 1 ) + +struct SalDriverData +{ + sal_uIntPtr mnSysSignature; + sal_uInt16 mnDriverOffset; + BYTE maDriverData[1]; +}; + +#pragma pack() + + +class WinSalGraphics; + +class WinSalInfoPrinter : public SalInfoPrinter +{ +public: + WinSalGraphics* mpGraphics; // current Printer graphics + OUString maDriverName; // printer driver name + OUString maDeviceName; // printer device name + OUString maPortName; // printer port name + HDC mhDC; // printer hdc + bool mbGraphics; // is Graphics used +public: + WinSalInfoPrinter(); + virtual ~WinSalInfoPrinter() override; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool Setup( weld::Window* pFrame, ImplJobSetup* pSetupData ) override; + virtual bool SetPrinterData( ImplJobSetup* pSetupData ) override; + virtual bool SetData( JobSetFlags nFlags, ImplJobSetup* pSetupData ) override; + virtual void GetPageInfo( const ImplJobSetup* pSetupData, + long& rOutWidth, long& rOutHeight, + Point& rPageOffset, + Size& rPaperSize ) override; + virtual sal_uInt32 GetCapabilities( const ImplJobSetup* pSetupData, PrinterCapType nType ) override; + virtual sal_uInt16 GetPaperBinCount( const ImplJobSetup* pSetupData ) override; + virtual OUString GetPaperBinName( const ImplJobSetup* pSetupData, sal_uInt16 nPaperBin ) override; + virtual void InitPaperFormats( const ImplJobSetup* pSetupData ) override; + virtual int GetLandscapeAngle( const ImplJobSetup* pSetupData ) override; +}; + + +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 + SalPrinterError mnError; // error code + sal_uIntPtr mnCopies; // copies + bool mbCollate; // collated copies + bool mbAbort; // Job Aborted + + bool mbValid; + +protected: + void DoEndDoc(HDC hDC); + +public: + WinSalPrinter(); + virtual ~WinSalPrinter() override; + + using SalPrinter::StartJob; + virtual bool StartJob( const OUString* pFileName, + const OUString& rJobName, + const OUString& rAppName, + sal_uInt32 nCopies, + bool bCollate, + bool bDirect, + ImplJobSetup* pSetupData ) override; + virtual bool EndJob() override; + virtual SalGraphics* StartPage( ImplJobSetup* pSetupData, bool bNewJobData ) override; + virtual void EndPage() override; + virtual SalPrinterError GetErrorCode() override; + + void markInvalid(); + bool isValid() const { return mbValid; } +}; + +#endif // INCLUDED_VCL_INC_WIN_SALPRN_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salsys.h b/vcl/inc/win/salsys.h new file mode 100644 index 000000000..03f627b5a --- /dev/null +++ b/vcl/inc/win/salsys.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALSYS_H +#define INCLUDED_VCL_INC_WIN_SALSYS_H + +#include + +#include +#include + +class WinSalSystem : public SalSystem +{ +public: + struct DisplayMonitor + { + OUString m_aName; + tools::Rectangle m_aArea; + + DisplayMonitor() {} + DisplayMonitor( const OUString& rName, + const tools::Rectangle& rArea ) + : m_aName( rName ), + m_aArea( rArea ) + { + } + }; +private: + std::vector m_aMonitors; + std::map m_aDeviceNameToMonitor; + unsigned int m_nPrimary; +public: + WinSalSystem() : m_nPrimary( 0 ) {} + virtual ~WinSalSystem() override; + + virtual unsigned int GetDisplayScreenCount() override; + virtual unsigned int GetDisplayBuiltInScreen() override; + virtual tools::Rectangle GetDisplayScreenPosSizePixel( unsigned int nScreen ) override; + virtual int ShowNativeMessageBox( const OUString& rTitle, + const OUString& rMessage) override; + bool initMonitors(); + // discards monitorinfo; used by WM_DISPLAYCHANGED handler + void clearMonitors(); + const std::vector& getMonitors() + { initMonitors(); return m_aMonitors;} + + bool handleMonitorCallback( sal_IntPtr /*HMONITOR*/, + sal_IntPtr /*HDC*/, + sal_IntPtr /*LPRECT*/ ); +}; + +#endif // INCLUDED_VCL_INC_WIN_SALSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/saltimer.h b/vcl/inc/win/saltimer.h new file mode 100644 index 000000000..a467de815 --- /dev/null +++ b/vcl/inc/win/saltimer.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALTIMER_H +#define INCLUDED_VCL_INC_WIN_SALTIMER_H + +#include + +class WinSalTimer final : public SalTimer, protected VersionedEvent +{ + // for access to Impl* functions + friend LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, bool& rDef ); + // for access to GetNextVersionedEvent + friend void CALLBACK SalTimerProc( PVOID data, BOOLEAN ); + // for access to ImplHandleElapsedTimer + friend bool ImplSalYield( bool bWait, bool bHandleAllCurrentEvents ); + + /** + * Identifier for our SetTimer based timer + */ + static constexpr UINT_PTR m_aWmTimerId = 0xdeadbeef; + + HANDLE m_nTimerId; ///< Windows timer id + bool m_bDirectTimeout; ///< timeout can be processed directly + bool m_bForceRealTimer; ///< enforce using a real timer for 0ms + bool m_bSetTimerRunning; ///< true, if a SetTimer is running + + void ImplStart( sal_uInt64 nMS ); + void ImplStop(); + void ImplHandleTimerEvent( WPARAM aWPARAM ); + void ImplHandleElapsedTimer(); + void ImplHandle_WM_TIMER( WPARAM aWPARAM ); + +public: + WinSalTimer(); + virtual ~WinSalTimer() override; + + virtual void Start(sal_uInt64 nMS) override; + virtual void Stop() override; + + inline bool IsDirectTimeout() const; + inline bool HasTimerElapsed() const; + + /** + * Enforces the usage of a real timer instead of the message queue + * + * Needed for Window resize processing, as this starts a modal event loop. + */ + void SetForceRealTimer( bool bVal ); + inline bool GetForceRealTimer() const; +}; + +inline bool WinSalTimer::IsDirectTimeout() const +{ + return m_bDirectTimeout; +} + +inline bool WinSalTimer::HasTimerElapsed() const +{ + return m_bDirectTimeout || ExistsValidEvent(); +} + +inline bool WinSalTimer::GetForceRealTimer() const +{ + return m_bForceRealTimer; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salvd.h b/vcl/inc/win/salvd.h new file mode 100644 index 000000000..4121d2c89 --- /dev/null +++ b/vcl/inc/win/salvd.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SALVD_H +#define INCLUDED_VCL_INC_WIN_SALVD_H + +#include +#include + +#include + +#include + +class WinSalGraphics; + + +class WinSalVirtualDevice : public SalVirtualDevice +{ +private: + HDC mhLocalDC; // HDC or 0 for Cache Device + ScopedHBITMAP mhBmp; // Memory Bitmap + HBITMAP mhDefBmp; // Default Bitmap + std::unique_ptr mpGraphics; // current VirDev graphics + WinSalVirtualDevice* mpNext; // next VirDev + sal_uInt16 mnBitCount; // BitCount (0 or 1) + bool mbGraphics; // is Graphics used + bool mbForeignDC; // uses a foreign DC instead of a bitmap + long mnWidth; + long mnHeight; + +public: + HDC getHDC() const { return mhLocalDC; } + WinSalGraphics* getGraphics() const { return mpGraphics.get(); } + void setGraphics(WinSalGraphics* pVirGraphics) { mpGraphics.reset(pVirGraphics); } + WinSalVirtualDevice* getNext() const { return mpNext; } + + WinSalVirtualDevice(HDC hDC = nullptr, HBITMAP hBMP = nullptr, sal_uInt16 nBitCount = 0, bool bForeignDC = false, long nWidth = 0, long nHeight = 0); + virtual ~WinSalVirtualDevice() override; + + virtual SalGraphics* AcquireGraphics() override; + virtual void ReleaseGraphics( SalGraphics* pGraphics ) override; + virtual bool SetSize( long nNewDX, long nNewDY ) override; + + static HBITMAP ImplCreateVirDevBitmap(HDC hDC, long nDX, long nDY, sal_uInt16 nBitCount, void **ppDummy); + + // SalGeometryProvider + virtual long GetWidth() const override { return mnWidth; } + virtual long GetHeight() const override { return mnHeight; } +}; + + +#endif // INCLUDED_VCL_INC_WIN_SALVD_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/scoped_gdi.hxx b/vcl/inc/win/scoped_gdi.hxx new file mode 100644 index 000000000..d02ad9545 --- /dev/null +++ b/vcl/inc/win/scoped_gdi.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_WIN_SCOPED_GDI_HXX +#define INCLUDED_VCL_INC_WIN_SCOPED_GDI_HXX + +#include +#include +#include + +#include + +template struct GDIDeleter +{ + using pointer = H; + void operator()(H h) { DeleterFunc(h); } +}; + +template +using ScopedGDI = std::unique_ptr>; + +using ScopedHBRUSH = ScopedGDI; +using ScopedHRGN = ScopedGDI; +using ScopedHDC = ScopedGDI; +using ScopedHPEN = ScopedGDI; +using ScopedHFONT = ScopedGDI; +using ScopedHBITMAP = ScopedGDI; + +template class ScopedSelectedGDI +{ +public: + ScopedSelectedGDI(HDC hDC, typename ScopedH::pointer h) + : m_hDC(hDC) + , m_hSelectedH(h) + , m_hOrigH(SelectorFunc(hDC, h)) + { + } + + ~ScopedSelectedGDI() { SelectorFunc(m_hDC, m_hOrigH); } + +private: + HDC m_hDC; + ScopedH m_hSelectedH; + typename ScopedH::pointer m_hOrigH; +}; + +using ScopedSelectedHPEN = ScopedSelectedGDI; +using ScopedSelectedHFONT = ScopedSelectedGDI; +using ScopedSelectedHBRUSH = ScopedSelectedGDI; + +template class ScopedCachedHDC +{ +public: + explicit ScopedCachedHDC(HBITMAP hBitmap) + : m_hDC(ImplGetCachedDC(ID, hBitmap)) + { + } + + ~ScopedCachedHDC() { ImplReleaseCachedDC(ID); } + + HDC get() const { return m_hDC; } + +private: + HDC m_hDC; +}; + +#endif // INCLUDED_VCL_INC_WIN_SCOPED_GDI_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/vcl/inc/win/svsys.h b/vcl/inc/win/svsys.h new file mode 100644 index 000000000..44cae93cf --- /dev/null +++ b/vcl/inc/win/svsys.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_SVSYS_H +#define INCLUDED_VCL_INC_WIN_SVSYS_H + +#ifdef _WIN32 +#ifndef INCLUDED_PRE_POST_WIN_H +#define INCLUDED_PRE_POST_WIN_H +#include +#include +#endif +#endif + +#endif // INCLUDED_VCL_INC_WIN_SVSYS_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/wincomp.hxx b/vcl/inc/win/wincomp.hxx new file mode 100644 index 000000000..05b4800e1 --- /dev/null +++ b/vcl/inc/win/wincomp.hxx @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_WINCOMP_HXX +#define INCLUDED_VCL_INC_WIN_WINCOMP_HXX + +#include + + +// Adjustments for TypeChecking + +inline HPEN SelectPen( HDC hDC, HPEN hPen ) +{ + return static_cast(SelectObject( hDC, static_cast(hPen) )); +} + +inline void DeletePen( HPEN hPen ) +{ + DeleteObject( static_cast(hPen) ); +} + +inline HPEN GetStockPen( int nObject ) +{ + return static_cast(GetStockObject( nObject )); +} + +inline HBRUSH SelectBrush( HDC hDC, HBRUSH hBrush ) +{ + return static_cast(SelectObject( hDC, static_cast(hBrush) )); +} + +inline void DeleteBrush( HBRUSH hBrush ) +{ + DeleteObject( static_cast(hBrush) ); +} + +inline HBRUSH GetStockBrush( int nObject ) +{ + return static_cast(GetStockObject( nObject )); +} + +inline HFONT SelectFont( HDC hDC, HFONT hFont ) +{ + return static_cast(SelectObject( hDC, static_cast(hFont) )); +} + +inline void DeleteFont( HFONT hFont ) +{ + DeleteObject( static_cast(hFont) ); +} + +inline HFONT GetStockFont( int nObject ) +{ + return static_cast(GetStockObject( nObject )); +} + +inline HBITMAP SelectBitmap( HDC hDC, HBITMAP hBitmap ) +{ + return static_cast(SelectObject( hDC, static_cast(hBitmap) )); +} + +inline void DeleteBitmap( HBITMAP hBitmap ) +{ + DeleteObject( static_cast(hBitmap) ); +} + +inline void DeleteRegion( HRGN hRegion ) +{ + DeleteObject( static_cast(hRegion) ); +} + +inline HPALETTE GetStockPalette( int nObject ) +{ + return static_cast(GetStockObject( nObject )); +} + +inline void DeletePalette( HPALETTE hPalette ) +{ + DeleteObject( static_cast(hPalette) ); +} + +inline void SetWindowStyle( HWND hWnd, DWORD nStyle ) +{ + SetWindowLongPtrW( hWnd, GWL_STYLE, nStyle ); +} + +inline DWORD GetWindowStyle( HWND hWnd ) +{ + return GetWindowLongPtrW( hWnd, GWL_STYLE ); +} + +inline void SetWindowExStyle( HWND hWnd, DWORD nStyle ) +{ + SetWindowLongPtrW( hWnd, GWL_EXSTYLE, nStyle ); +} + +inline DWORD GetWindowExStyle( HWND hWnd ) +{ + return GetWindowLongPtrW( hWnd, GWL_EXSTYLE ); +} + +inline BOOL IsMinimized( HWND hWnd ) +{ + return IsIconic( hWnd ); +} + +inline BOOL IsMaximized( HWND hWnd ) +{ + return IsZoomed( hWnd ); +} + +inline void SetWindowFont( HWND hWnd, HFONT hFont, BOOL bRedraw ) +{ + SendMessageW( hWnd, WM_SETFONT, reinterpret_cast(hFont), MAKELPARAM(static_cast(bRedraw),0) ); +} + +inline HFONT GetWindowFont( HWND hWnd ) +{ + return reinterpret_cast(SendMessageW( hWnd, WM_GETFONT, 0, 0 )); +} + +inline void SetClassCursor( HWND hWnd, HCURSOR hCursor ) +{ + SetClassLongPtr( hWnd, GCLP_HCURSOR, reinterpret_cast(hCursor) ); +} + +inline HCURSOR GetClassCursor( HWND hWnd ) +{ + return reinterpret_cast(GetClassLongPtr( hWnd, GCLP_HCURSOR )); +} + +inline void SetClassIcon( HWND hWnd, HICON hIcon ) +{ + SetClassLongPtr( hWnd, GCLP_HICON, reinterpret_cast(hIcon) ); +} + +inline HICON GetClassIcon( HWND hWnd ) +{ + return reinterpret_cast(GetClassLongPtr( hWnd, GCLP_HICON )); +} + +inline HBRUSH SetClassBrush( HWND hWnd, HBRUSH hBrush ) +{ + return reinterpret_cast(SetClassLongPtr( hWnd, GCLP_HBRBACKGROUND, reinterpret_cast(hBrush) )); +} + +inline HBRUSH GetClassBrush( HWND hWnd ) +{ + return reinterpret_cast(GetClassLongPtr( hWnd, GCLP_HBRBACKGROUND )); +} + +inline HINSTANCE GetWindowInstance( HWND hWnd ) +{ + return reinterpret_cast(GetWindowLongPtrW( hWnd, GWLP_HINSTANCE )); +} + + +#define MOUSEZ_CLASSNAME L"MouseZ" // wheel window class +#define MOUSEZ_TITLE L"Magellan MSWHEEL" // wheel window title + +#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME) +#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE) + +#define MSH_SCROLL_LINES L"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 + + +// - 5.0 extensions - + +#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 // INCLUDED_VCL_INC_WIN_WINCOMP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/wingdiimpl.hxx b/vcl/inc/win/wingdiimpl.hxx new file mode 100644 index 000000000..679be2c36 --- /dev/null +++ b/vcl/inc/win/wingdiimpl.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_WIN_WINGDIIMPL_HXX +#define INCLUDED_VCL_INC_WIN_WINGDIIMPL_HXX + +#include +#include + +class ControlCacheKey; + +// Base class for some functionality that OpenGL/Skia/GDI backends must each implement. +class WinSalGraphicsImplBase +{ +public: + virtual ~WinSalGraphicsImplBase(){}; + + // If true is returned, the following functions are used for drawing controls. + virtual bool UseRenderNativeControl() const { return false; } + virtual bool TryRenderCachedNativeControl(const ControlCacheKey& /*rControlCacheKey*/, + int /*nX*/, int /*nY*/) + { + abort(); + }; + virtual bool RenderAndCacheNativeControl(CompatibleDC& /*rWhite*/, CompatibleDC& /*rBlack*/, + int /*nX*/, int /*nY*/, + ControlCacheKey& /*aControlCacheKey*/) + { + abort(); + }; + + virtual void ClearDevFontCache(){}; + + // Implementation for WinSalGraphics::DrawTextLayout(). + // Returns true if handled, if false, then WinSalGraphics will handle it itself. + virtual bool DrawTextLayout(const GenericSalLayout&) { return false; } + // If true is returned, the following functions are used for text rendering. + virtual bool UseTextDraw() const { return false; } + virtual void PreDrawText() {} + virtual void PostDrawText() {} + virtual void DrawTextMask(CompatibleDC::Texture* /*rTexture*/, Color /*nMaskColor*/, + const SalTwoRect& /*rPosAry*/) + { + abort(); + }; + virtual void DeferredTextDraw(const CompatibleDC::Texture* /*pTexture*/, Color /*nMaskColor*/, + const SalTwoRect& /*rPosAry*/) + { + abort(); + }; +}; + +#endif // INCLUDED_VCL_INC_WIN_WINGDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx new file mode 100644 index 000000000..35a855a37 --- /dev/null +++ b/vcl/inc/win/winlayout.hxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WIN_WINLAYOUT_HXX +#define INCLUDED_VCL_INC_WIN_WINLAYOUT_HXX + +#include + +#include +#include +#include +#include + +class WinFontInstance; + +namespace +{ +// Extra space at the top and bottom of the glyph in total = tmHeight / GLYPH_SPACE_RATIO; +const int GLYPH_SPACE_RATIO = 8; +// Border size at the top of the glyph = tmHeight / GLYPH_OFFSET_RATIO; +const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2; +} + +struct WinGlyphDrawElement +{ + tools::Rectangle maLocation; + int maLeftOverhangs; + std::unique_ptr maTexture; + int mnBaselineOffset; + int mnHeight; + bool mbVertical; + + int getExtraSpace() const + { + return std::max(mnHeight / GLYPH_SPACE_RATIO, 4); + } + + int getExtraOffset() const + { + return std::max(mnHeight / GLYPH_OFFSET_RATIO, 2); + } +}; + +class WinGlyphCache; + +struct GlobalWinGlyphCache +{ + o3tl::sorted_vector maWinGlyphCaches; + + static GlobalWinGlyphCache * get(); + + virtual ~GlobalWinGlyphCache() {} + virtual bool AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) = 0; + virtual void NotifyElementUsed(WinGlyphDrawElement& /*rElement*/) {} + virtual void Prune() {} +}; + +class WinGlyphCache +{ +protected: + std::unordered_map maWinTextureCache; + +public: + WinGlyphCache() + { + if(GlobalWinGlyphCache* c = GlobalWinGlyphCache::get()) + c->maWinGlyphCaches.insert(this); + } + + virtual ~WinGlyphCache() + { + if(GlobalWinGlyphCache* c = GlobalWinGlyphCache::get()) + c->maWinGlyphCaches.erase(this); + } + + void PutDrawElementInCache(WinGlyphDrawElement&& rElement, int nGlyphIndex) + { + assert(GlobalWinGlyphCache::get()); + assert(!IsGlyphCached(nGlyphIndex)); + maWinTextureCache[nGlyphIndex] = std::move( rElement ); + } + + WinGlyphDrawElement& GetDrawElement(int nGlyphIndex) + { + assert(GlobalWinGlyphCache::get()); + assert(IsGlyphCached(nGlyphIndex)); + WinGlyphDrawElement& element = maWinTextureCache[nGlyphIndex]; + GlobalWinGlyphCache::get()->NotifyElementUsed(element); + return element; + } + + bool IsGlyphCached(int nGlyphIndex) const + { + return maWinTextureCache.find(nGlyphIndex) != maWinTextureCache.end(); + } +}; + +// win32 specific logical font instance +class WinFontInstance : public LogicalFontInstance +{ + friend rtl::Reference WinFontFace::CreateFontInstance(const FontSelectPattern&) const; + +public: + ~WinFontInstance() override; + + bool hasHScale() const; + float getHScale() const; + + void SetGraphics(WinSalGraphics*); + WinSalGraphics* GetGraphics() const { return m_pGraphics; } + + HFONT GetHFONT() const { return m_hFont; } + float GetScale() const { return m_fScale; } + + // Prevent deletion of the HFONT in the WinFontInstance destructor + // Used for the ScopedFont handling + void SetHFONT(HFONT hFont) { m_hFont = hFont; } + + const WinFontFace * GetFontFace() const { return static_cast(LogicalFontInstance::GetFontFace()); } + WinFontFace * GetFontFace() { return static_cast(LogicalFontInstance::GetFontFace()); } + + bool CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, SalGraphics& rGraphics, const GenericSalLayout& rLayout); + WinGlyphCache& GetWinGlyphCache() { return maWinGlyphCache; } + + bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; + +private: + explicit WinFontInstance(const WinFontFace&, const FontSelectPattern&); + + hb_font_t* ImplInitHbFont() override; + bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; + + WinSalGraphics *m_pGraphics; + HFONT m_hFont; + float m_fScale; + WinGlyphCache maWinGlyphCache; +}; + +class TextOutRenderer +{ +protected: + explicit TextOutRenderer() = default; + TextOutRenderer(const TextOutRenderer &) = delete; + TextOutRenderer & operator = (const TextOutRenderer &) = delete; + +public: + static TextOutRenderer & get(bool bUseDWrite); + + virtual ~TextOutRenderer() = default; + + virtual bool operator ()(GenericSalLayout const &rLayout, + SalGraphics &rGraphics, + HDC hDC) = 0; +}; + +class ExTextOutRenderer : public TextOutRenderer +{ + ExTextOutRenderer(const ExTextOutRenderer &) = delete; + ExTextOutRenderer & operator = (const ExTextOutRenderer &) = delete; + +public: + explicit ExTextOutRenderer() = default; + + bool operator ()(GenericSalLayout const &rLayout, + SalGraphics &rGraphics, + HDC hDC) override; +}; + +#endif // INCLUDED_VCL_INC_WIN_WINLAYOUT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/window.h b/vcl/inc/window.h new file mode 100644 index 000000000..6b362e7d3 --- /dev/null +++ b/vcl/inc/window.h @@ -0,0 +1,438 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_WINDOW_H +#define INCLUDED_VCL_INC_WINDOW_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +class FixedText; +class VclSizeGroup; +class VirtualDevice; +class PhysicalFontCollection; +class ImplFontCache; +class VCLXWindow; +class WindowStateData; +class SalFrame; +class SalObject; +enum class MouseEventModifiers; +enum class MouseNotifyEvent; +enum class ActivateModeFlags; +enum class DialogControlFlags; +enum class GetFocusFlags; +enum class ParentClipMode; +enum class SalEvent; + +namespace com::sun::star { + + namespace accessibility { + class XAccessible; + class XAccessibleContext; + class XAccessibleEditableText; + } + + namespace rendering { + class XCanvas; + } + + 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; + } + } +} + +VCL_DLLPUBLIC Size bestmaxFrameSizeForScreenSize(const Size &rScreenSize); + +//return true if this window and its stack of containers are all shown +bool isVisibleInLayout(const vcl::Window *pWindow); + +//return true if this window and its stack of containers are all enabled +bool isEnabledInLayout(const vcl::Window *pWindow); + +bool ImplWindowFrameProc( vcl::Window* pInst, SalEvent nEvent, const void* pEvent ); + +struct ImplWinData +{ + std::optional + mpExtOldText; + std::unique_ptr + mpExtOldAttrAry; + std::optional + mpCursorRect; + long mnCursorExtWidth; + bool mbVertical; + std::unique_ptr + mpCompositionCharRects; + long mnCompositionCharRects; + std::optional + mpFocusRect; + std::optional + mpTrackRect; + ShowTrackFlags mnTrackFlags; + sal_uInt16 mnIsTopWindow; + bool mbMouseOver; //< tracks mouse over for native widget paint effect + bool mbEnableNativeWidget; //< toggle native widget rendering + ::std::list< VclPtr > + maTopWindowChildren; + + ImplWinData(); + ~ImplWinData(); +}; + +struct ImplFrameData +{ + Idle maPaintIdle; //< paint idle handler + Idle maResizeIdle; //< resize timer + InputContext maOldInputContext; //< last set Input Context + VclPtr mpNextFrame; //< next frame window + VclPtr mpFirstOverlap; //< first overlap vcl::Window + VclPtr mpFocusWin; //< focus window (is also set, when frame doesn't have the focus) + VclPtr mpMouseMoveWin; //< last window, where MouseMove() called + VclPtr mpMouseDownWin; //< last window, where MouseButtonDown() called + std::vector > maOwnerDrawList; //< List of system windows with owner draw decoration + std::shared_ptr mxFontCollection; //< Font-List for this frame + std::shared_ptr mxFontCache; //< Font-Cache for this frame + sal_Int32 mnDPIX; //< Original Screen Resolution + sal_Int32 mnDPIY; //< Original Screen Resolution + ImplSVEvent * mnFocusId; //< FocusId for PostUserLink + ImplSVEvent * 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 + sal_uInt16 mnModalMode; //< frame based modal count (app based makes no sense anymore) + sal_uInt64 mnMouseDownTime; //< mouse button down time for double click + sal_uInt16 mnClickCount; //< mouse click count + sal_uInt16 mnFirstMouseCode; //< mouse code by mousebuttondown + sal_uInt16 mnMouseCode; //< mouse code + MouseEventModifiers mnMouseMode; //< mouse mode + 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, when sending the event + bool mbInSysObjFocusHdl; //< within a SysChildren's GetFocus handler + bool mbInSysObjToTopHdl; //< within a SysChildren's ToTop handler + bool mbSysObjFocus; //< does a SysChild have focus + sal_Int32 mnTouchPanPosition; + + css::uno::Reference< css::datatransfer::dnd::XDragSource > mxDragSource; + css::uno::Reference< css::datatransfer::dnd::XDropTarget > mxDropTarget; + css::uno::Reference< css::datatransfer::dnd::XDropTargetListener > mxDropTargetListener; + css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard; + css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxSelection; + + bool mbInternalDragGestureRecognizer; + VclPtr mpBuffer; ///< Buffer for the double-buffering + bool mbInBufferedPaint; ///< PaintHelper is in the process of painting into this buffer. + tools::Rectangle maBufferedRect; ///< Rectangle in the buffer that has to be painted to the screen. + + ImplFrameData( vcl::Window *pWindow ); +}; + +struct ImplAccessibleInfos +{ + sal_uInt16 nAccessibleRole; + std::optional + pAccessibleName; + std::optional + pAccessibleDescription; + VclPtr pLabeledByWindow; + VclPtr pLabelForWindow; + VclPtr pMemberOfWindow; + + ImplAccessibleInfos(); + ~ImplAccessibleInfos(); +}; + +enum AlwaysInputMode { AlwaysInputNone = 0, AlwaysInputEnabled = 1, AlwaysInputDisabled =2 }; + +enum class ImplPaintFlags { + NONE = 0x0000, + Paint = 0x0001, + PaintAll = 0x0002, + PaintAllChildren = 0x0004, + PaintChildren = 0x0008, + Erase = 0x0010, + CheckRtl = 0x0020, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + +class WindowImpl +{ +private: + WindowImpl(const WindowImpl&) = delete; + WindowImpl& operator=(const WindowImpl&) = delete; +public: + WindowImpl( WindowType ); + ~WindowImpl(); + + ImplWinData* mpWinData; + ImplFrameData* mpFrameData; + SalFrame* mpFrame; + SalObject* mpSysObj; + VclPtr mpFrameWindow; + VclPtr mpOverlapWindow; + VclPtr mpBorderWindow; + VclPtr mpClientWindow; + VclPtr mpParent; + VclPtr mpRealParent; + VclPtr mpFirstChild; + VclPtr mpLastChild; + VclPtr mpFirstOverlap; + VclPtr mpLastOverlap; + VclPtr mpPrev; + VclPtr mpNext; + VclPtr mpNextOverlap; + VclPtr mpLastFocusWindow; + VclPtr mpDlgCtrlDownWindow; + std::vector> maEventListeners; + int mnEventListenersIteratingCount; + std::set> maEventListenersDeleted; + std::vector> maChildEventListeners; + int mnChildEventListenersIteratingCount; + std::set> maChildEventListenersDeleted; + Link maHelpRequestHdl; + Link maMnemonicActivateHdl; + Link maDumpAsPropertyTreeHdl; + + // The canvas interface for this VCL window. Is persistent after the first GetCanvas() call + css::uno::WeakReference< css::rendering::XCanvas > mxCanvas; + + vcl::Cursor* mpCursor; + PointerStyle maPointer; + Fraction maZoom; + OUString maText; + std::unique_ptr + mpControlFont; + Color maControlForeground; + Color maControlBackground; + sal_Int32 mnLeftBorder; + sal_Int32 mnTopBorder; + sal_Int32 mnRightBorder; + sal_Int32 mnBottomBorder; + sal_Int32 mnWidthRequest; + sal_Int32 mnHeightRequest; + sal_Int32 mnOptimalWidthCache; + sal_Int32 mnOptimalHeightCache; + long mnX; + long mnY; + long mnAbsScreenX; + Point maPos; + OString maHelpId; + OUString maHelpText; + OUString maQuickHelpText; + OUString maID; + InputContext maInputContext; + css::uno::Reference< css::awt::XWindowPeer > mxWindowPeer; + css::uno::Reference< css::accessibility::XAccessible > mxAccessible; + std::shared_ptr< VclSizeGroup > m_xSizeGroup; + std::vector> m_aMnemonicLabels; + std::unique_ptr mpAccessibleInfos; + VCLXWindow* mpVCLXWindow; + vcl::Region maWinRegion; //< region to 'shape' the VCL window (frame coordinates) + vcl::Region maWinClipRegion; //< the (clipping) region that finally corresponds to the VCL window (frame coordinates) + vcl::Region maInvalidateRegion; //< region that has to be redrawn (frame coordinates) + std::unique_ptr mpChildClipRegion; //< child clip region if CLIPCHILDREN is set (frame coordinates) + vcl::Region* mpPaintRegion; //< only set during Paint() method call (window coordinates) + WinBits mnStyle; + WinBits mnPrevStyle; + WindowExtendedStyle mnExtendedStyle; + WindowType mnType; + ControlPart mnNativeBackground; + sal_uInt16 mnWaitCount; + ImplPaintFlags mnPaintFlags; + GetFocusFlags mnGetFocusFlags; + ParentClipMode mnParentClipMode; + ActivateModeFlags mnActivateMode; + DialogControlFlags mnDlgCtrlFlags; + AlwaysInputMode meAlwaysInputMode; + VclAlign meHalign; + VclAlign meValign; + VclPackType mePackType; + sal_Int32 mnPadding; + sal_Int32 mnGridHeight; + sal_Int32 mnGridLeftAttach; + sal_Int32 mnGridTopAttach; + sal_Int32 mnGridWidth; + sal_Int32 mnBorderWidth; + sal_Int32 mnMarginLeft; + sal_Int32 mnMarginRight; + sal_Int32 mnMarginTop; + sal_Int32 mnMarginBottom; + bool mbFrame:1, + mbBorderWin:1, + mbOverlapWin:1, + mbSysWin:1, + mbDialog:1, + mbDockWin:1, + mbFloatWin:1, + mbPushButton:1, + mbVisible:1, + mbDisabled:1, + mbInputDisabled:1, + mbNoUpdate:1, + mbNoParentUpdate:1, + mbActive:1, + mbReallyVisible:1, + mbReallyShown:1, + mbInInitShow:1, + mbChildPtrOverwrite:1, + mbNoPtrVisible:1, + mbPaintFrame:1, + mbInPaint: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, + mbInDispose: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, + mbHelpTextDynamic:1, + mbFakeFocusSet:1, + mbHexpand:1, + mbVexpand:1, + mbExpand:1, + mbFill:1, + mbSecondary:1, + mbNonHomogeneous:1, + mbDoubleBufferingRequested:1; + + css::uno::Reference< css::uno::XInterface > mxDNDListenerContainer; + + const vcl::ILibreOfficeKitNotifier* mpLOKNotifier; ///< To emit the LOK callbacks eg. for dialog tunneling. + vcl::LOKWindowId mnLOKWindowId; ///< ID of this specific window. + bool mbLOKParentNotifier; +}; + +namespace vcl +{ +/// Sets up the buffer to have settings matching the window, and restores the original state in the dtor. +class VCL_DLLPUBLIC PaintBufferGuard +{ + ImplFrameData* mpFrameData; + VclPtr m_pWindow; + bool mbBackground; + Wallpaper maBackground; + AllSettings maSettings; + long mnOutOffX; + long mnOutOffY; + tools::Rectangle m_aPaintRect; +public: + PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow); + ~PaintBufferGuard(); + /// If this is called, then the dtor will also copy rRectangle to the window from the buffer, before restoring the state. + void SetPaintRect(const tools::Rectangle& rRectangle); + /// Returns either the frame's buffer or the window, in case of no buffering. + vcl::RenderContext* GetRenderContext(); +}; +} + +// helper methods + +bool ImplHandleMouseEvent( const VclPtr& xWindow, MouseNotifyEvent nSVEvent, bool bMouseLeave, + long nX, long nY, sal_uInt64 nMsgTime, + sal_uInt16 nCode, MouseEventModifiers nMode ); +void ImplHandleResize( vcl::Window* pWindow, long nNewWidth, long nNewHeight ); + +VCL_DLLPUBLIC void ImplWindowStateFromStr(WindowStateData& rData, const OString& rStr); + +VCL_DLLPUBLIC css::uno::Reference +FindFocusedEditableText(css::uno::Reference const&); + +#endif // INCLUDED_VCL_INC_WINDOW_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/wizdlg.hxx b/vcl/inc/wizdlg.hxx new file mode 100644 index 000000000..2c82b3ab8 --- /dev/null +++ b/vcl/inc/wizdlg.hxx @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_WIZDLG_HXX +#define INCLUDED_VCL_WIZDLG_HXX + +#include +#include +#include +#include +#include + +struct ImplWizPageData +{ + ImplWizPageData* mpNext; + VclPtr mpPage; +}; + +namespace vcl +{ + struct RoadmapWizardImpl; + class RoadmapWizard; + + namespace RoadmapWizardTypes + { + typedef VclPtr (* RoadmapPageFactory)( RoadmapWizard& ); + }; + + //= RoadmapWizard + + /** wizard for a roadmap + + The basic new concept introduced is a path:
+ A path is a sequence of states, which are to be executed in a linear order. + Elements in the path can be skipped, depending on choices the user makes. + + In the most simple wizards, you will have only one path consisting of n elements, + which are to be visited successively. + + In a slightly more complex wizard, you will have one linear path, were certain + steps might be skipped due to user input. For instance, the user may decide to not specify + certain aspects of the to-be-created object (e.g. by unchecking a check box), + and the wizard then will simply disable the step which corresponds to this step. + + In a yet more advanced wizards, you will have several paths of length n1 and + n2, which share at least the first k states (where k + is at least 1), and an arbitrary number of other states. + */ + class RoadmapWizard : public Dialog + { + private: + Idle maWizardLayoutIdle; + Size maPageSize; + ImplWizPageData* mpFirstPage; + ImplWizButtonData* mpFirstBtn; + VclPtr mpCurTabPage; + VclPtr mpPrevBtn; + VclPtr mpNextBtn; + VclPtr mpViewWindow; + sal_uInt16 mnCurLevel; + sal_Int16 mnLeftAlignCount; + bool mbEmptyViewMargin; + + DECL_LINK( ImplHandleWizardLayoutTimerHdl, Timer*, void ); + + // IMPORTANT: + // traveling pages should not be done by calling these base class member, some mechanisms of this class + // here (e.g. committing page data) depend on having full control over page traveling. + // So use the travelXXX methods if you need to travel + + protected: + long LogicalCoordinateToPixel(int iCoordinate); + /**sets the number of buttons which should be left-aligned. Normally, buttons are right-aligned. + + only to be used during construction, before any layouting happened + */ + void SetLeftAlignedButtonCount( sal_Int16 _nCount ); + + void CalcAndSetSize(); + + public: + VclPtr m_pFinish; + VclPtr m_pCancel; + VclPtr m_pNextPage; + VclPtr m_pPrevPage; + VclPtr m_pHelp; + + private: + std::unique_ptr m_xWizardImpl; + // hold members in this structure to allow keeping compatible when members are added + std::unique_ptr m_xRoadmapImpl; + + public: + RoadmapWizard(vcl::Window* pParent, WinBits nStyle = WB_STDDIALOG, InitFlag eFlag = InitFlag::Default); + virtual ~RoadmapWizard( ) override; + virtual void dispose() override; + + virtual void Resize() override; + virtual void StateChanged( StateChangedType nStateChange ) override; + virtual bool EventNotify( NotifyEvent& rNEvt ) override; + + void ActivatePage(); + + virtual void queue_resize(StateChangedType eReason = StateChangedType::Layout) override; + + bool ShowPage( sal_uInt16 nLevel ); + bool Finish( long nResult = 0 ); + sal_uInt16 GetCurLevel() const { return mnCurLevel; } + + void AddPage( TabPage* pPage ); + void RemovePage( TabPage* pPage ); + void SetPage( sal_uInt16 nLevel, TabPage* pPage ); + TabPage* GetPage( sal_uInt16 nLevel ) const; + + void AddButton( Button* pButton, long nOffset = 0 ); + void RemoveButton( Button* pButton ); + + void SetPageSizePixel( const Size& rSize ) { maPageSize = rSize; } + const Size& GetPageSizePixel() const { return maPageSize; } + + /// enable (or disable) buttons + void enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable); + + /// determines whether there is a next state to which we can advance + bool canAdvance() const; + + void SetRoadmapHelpId( const OString& _rId ); + + void InsertRoadmapItem(int nIndex, const OUString& rLabel, int nId, bool bEnabled); + void DeleteRoadmapItems(); + int GetCurrentRoadmapItemID() const; + void SelectRoadmapItemByID(int nId); + void SetItemSelectHdl( const Link& _rHdl ); + void ShowRoadmap(bool bShow); + + FactoryFunction GetUITestFactory() const override; + + protected: + + /// to override to create new pages + VclPtr createPage(WizardTypes::WizardState nState); + + /// will be called when a new page is about to be displayed + void enterState(WizardTypes::WizardState _nState); + + /** will be called when the current state is about to be left for the given reason + + The base implementation in this class will simply call OWizardPage::commitPage + for the current page, and return whatever this call returns. + + @param _eReason + The reason why the state is to be left. + @return + if and only if the page is allowed to be left + */ + bool prepareLeaveCurrentState( WizardTypes::CommitPageReason eReason ); + + /** determine the next state to travel from the given one + + This method ensures that traveling happens along the active path. + + Return WZS_INVALID_STATE to prevent traveling. + + @see activatePath + */ + WizardTypes::WizardState determineNextState(WizardTypes::WizardState nCurrentState) const; + + /// travel to the next state + bool travelNext(); + + /// travel to the previous state + bool travelPrevious(); + + /** enables the automatic enabled/disabled state of the "Next" button + + If this is , then upon entering a new state, the "Next" button will automatically be + enabled if and only if determineNextState does not return WZS_INVALID_STATE. + */ + bool isAutomaticNextButtonStateEnabled() const; + + /** removes a page from the history. Should be called when the page is being disabled + */ + void removePageFromHistory(WizardTypes::WizardState nToRemove); + + /** skips one or more states, until a given state is reached + + The method behaves as if from the current state, travelNexts were called + successively, until _nTargetState is reached, but without actually creating or + displaying the \EDntermediate pages. + + The skipped states appear in the state history, so travelPrevious will make use of them. + + @return + if and only if traveling was successful + + @see skip + @see skipBackwardUntil + */ + bool skipUntil(WizardTypes::WizardState nTargetState); + + /** moves back one or more states, until a given state is reached + + This method allows traveling backwards more than one state without actually showing the intermediate + states. + + For instance, if you want to travel two steps backward at a time, you could used + two travelPrevious calls, but this would show both pages, which is not necessary, + since you're interested in the target page only. Using skipBackwardUntil relieves + you of this. + + @return + if and only if traveling was successful + + @see skipUntil + @see skip + */ + bool skipBackwardUntil(WizardTypes::WizardState nTargetState); + + /** returns the current state of the machine + + Vulgo, this is the identifier of the current tab page :) + */ + WizardTypes::WizardState getCurrentState() const { return GetCurLevel(); } + + static IWizardPageController* getPageController( TabPage* _pCurrentPage ); + + /** returns a human readable name for a given state + + There is a default implementation for this method, which returns the display name + as given in a call to describeState. If there is no description for the given state, + this is worth an assertion in a non-product build, and then an empty string is + returned. + */ + OUString getStateDisplayName(WizardTypes::WizardState nState) const; + + private: + DECL_LINK( OnRoadmapItemSelected, LinkParamNone*, void ); + + /** updates the roadmap control to show the given path, as far as possible + (modulo conflicts with other paths) + */ + void implUpdateRoadmap( ); + + public: + class AccessGuard + { + friend class RoadmapWizardTravelSuspension; + private: + AccessGuard() { } + }; + + void suspendTraveling( AccessGuard ); + void resumeTraveling( AccessGuard ); + bool isTravelingSuspended() const; + + protected: + TabPage* GetOrCreatePage(const WizardTypes::WizardState i_nState); + + private: + void ImplCalcSize( Size& rSize ); + void ImplPosCtrls(); + void ImplPosTabPage(); + void ImplShowTabPage( TabPage* pPage ); + TabPage* ImplGetPage( sal_uInt16 nLevel ) const; + + + DECL_LINK(OnNextPage, Button*, void); + DECL_LINK(OnPrevPage, Button*, void); + DECL_LINK(OnFinish, Button*, void); + + void implUpdateTitle(); + void implConstruct( const WizardButtonFlags _nButtonFlags ); + }; + + /// helper class to temporarily suspend any traveling in the wizard + class RoadmapWizardTravelSuspension + { + public: + RoadmapWizardTravelSuspension(RoadmapWizard& rWizard) + : m_pOWizard(&rWizard) + { + m_pOWizard->suspendTraveling(RoadmapWizard::AccessGuard()); + } + + ~RoadmapWizardTravelSuspension() + { + if (m_pOWizard) + m_pOWizard->resumeTraveling(RoadmapWizard::AccessGuard()); + } + + private: + VclPtr m_pOWizard; + }; + +} // namespace vcl + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/DataFlavorMapping.cxx b/vcl/ios/DataFlavorMapping.cxx new file mode 100644 index 000000000..88b0e6199 --- /dev/null +++ b/vcl/ios/DataFlavorMapping.cxx @@ -0,0 +1,571 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "DataFlavorMapping.hxx" +#include "HtmlFmtFlt.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +using namespace css::datatransfer; +using namespace css::uno; +using namespace css::lang; +using namespace cppu; + +namespace +{ +/* 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 == cppu::UnoType>::get()) + || (dtype == cppu::UnoType::get()))); +} + +OUString NSStringToOUString(const NSString* cfString) +{ + 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]; +} + +NSString* PBTYPE_PLAINTEXT = (__bridge NSString*)kUTTypePlainText; +// Nope. See commented-out use below. +// NSString* PBTYPE_UTF8PLAINTEXT = (__bridge NSString*)kUTTypeUTF8PlainText; +NSString* PBTYPE_RTF = (__bridge NSString*)kUTTypeRTF; +NSString* PBTYPE_PNG = (__bridge NSString*)kUTTypePNG; +NSString* PBTYPE_JPEG = (__bridge NSString*)kUTTypeJPEG; +NSString* PBTYPE_HTML = (__bridge NSString*)kUTTypeHTML; +NSString* PBTYPE_PDF = (__bridge NSString*)kUTTypePDF; +NSString* PBTYPE_SESX + = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; +NSString* PBTYPE_SLSDX = @"application/" + @"x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link " + @"Source Descriptor (XML)\""; +NSString* PBTYPE_LSX + = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\""; +NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star " + @"Embedded Object (XML)\""; +NSString* PBTYPE_SVXB + = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\""; +NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""; +NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star " + @"Object Descriptor (XML)\""; +NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal"; + +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_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_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star " + "Object Descriptor (XML)\""; +const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal"; + +struct FlavorMap +{ + NSString* SystemFlavor; + const char* OOoFlavor; + const char* HumanPresentableName; + bool DataTypeOUString; // sequence otherwise +}; + +static const FlavorMap flavorMap[] + = { { PBTYPE_PLAINTEXT, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true }, + // Nope. The LO code does not understand text/plain in UTF-8. Which is a shame. + // PBTYPE_UTF8PLAINTEXT, "text/plain;charset=utf-8", "Unicode Text (UTF-8)", false }, + { PBTYPE_RTF, "text/rtf", "Rich Text Format", false }, + { PBTYPE_PNG, "image/png", "Portable Network Graphics", false }, + { PBTYPE_JPEG, "image/jpeg", "JPEG", false }, + { PBTYPE_HTML, "text/html", "Plain HTML", false }, + { PBTYPE_PDF, "application/pdf", "PDF File", false }, + { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", false }, + { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false }, + { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", false }, + { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", false }, + { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false }, + { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", false }, + { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", false }, + { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data", false } }; + +#define SIZE_FLAVOR_MAP (sizeof(flavorMap) / sizeof(FlavorMap)) + +inline bool isByteSequenceType(const Type& theType) +{ + return (theType == cppu::UnoType>::get()); +} + +inline bool isOUStringType(const Type& theType) +{ + return (theType == cppu::UnoType::get()); +} + +} // unnamed namespace + +/* A base class for other data provider. + */ +class DataProviderBaseImpl : public DataProvider +{ +public: + DataProviderBaseImpl(const Any& data); + DataProviderBaseImpl(id data); + virtual ~DataProviderBaseImpl() override; + +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); + + NSData* getSystemData() override; + Any getOOoData() override; +}; + +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 <<= OUString(static_cast([mSystemData bytes]), [mSystemData length], + RTL_TEXTENCODING_UTF8); + } + else + { + oOOData = mData; + } + + return oOOData; +} + +class ByteSequenceDataProvider : public DataProviderBaseImpl +{ +public: + ByteSequenceDataProvider(const Any& data); + ByteSequenceDataProvider(NSData* data); + + NSData* getSystemData() override; + Any getOOoData() override; +}; + +ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) + : DataProviderBaseImpl(data) +{ +} + +ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) + : DataProviderBaseImpl(data) +{ +} + +NSData* ByteSequenceDataProvider::getSystemData() +{ + Sequence rawData; + mData >>= rawData; + + return [NSData dataWithBytes:rawData.getArray() length:rawData.getLength()]; +} + +Any ByteSequenceDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence byteSequence; + byteSequence.realloc(flavorDataLength); + memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength); + oOOData <<= byteSequence; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +class HTMLFormatDataProvider : public DataProviderBaseImpl +{ +public: + HTMLFormatDataProvider(NSData* data); + + NSData* getSystemData() override; + Any getOOoData() override; +}; + +HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) + : DataProviderBaseImpl(data) +{ +} + +NSData* HTMLFormatDataProvider::getSystemData() +{ + Sequence textHtmlData; + mData >>= textHtmlData; + + Sequence htmlFormatData = TextHtmlToHTMLFormat(textHtmlData); + + return [NSData dataWithBytes:htmlFormatData.getArray() length:htmlFormatData.getLength()]; +} + +Any HTMLFormatDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence unkHtmlData; + + unkHtmlData.realloc(flavorDataLength); + memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength); + + Sequence* pPlainHtml = &unkHtmlData; + Sequence plainHtml; + + if (isHTMLFormat(unkHtmlData)) + { + plainHtml = HTMLFormatToTextHtml(unkHtmlData); + pPlainHtml = &plainHtml; + } + + oOOData <<= *pPlainHtml; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +DataFlavorMapper::DataFlavorMapper() +{ + Reference xContext = comphelper::getProcessComponentContext(); + mrXMimeCntFactory = MimeContentTypeFactory::create(xContext); +} + +DataFlavorMapper::~DataFlavorMapper() +{ + // release potential NSStrings + for (OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end(); + ++it) + { + [it->second release]; + it->second = nil; + } +} + +DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(const NSString* systemDataFlavor) const +{ + DataFlavor oOOFlavor; + + for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++) + { + if ([systemDataFlavor + caseInsensitiveCompare:const_cast(flavorMap[i].SystemFlavor)] + == NSOrderedSame) + { + oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor); + oOOFlavor.HumanPresentableName + = OUString::createFromAscii(flavorMap[i].HumanPresentableName); + oOOFlavor.DataType = flavorMap[i].DataTypeOUString + ? cppu::UnoType::get() + : cppu::UnoType>::get(); + return oOOFlavor; + } + } // for + + // look if this might be an internal type; if it comes in here it must have + // been through openOfficeToSystemFlavor before, so it should then be in the map + OUString aTryFlavor(NSStringToOUString(systemDataFlavor)); + if (maOfficeOnlyTypes.find(aTryFlavor) != maOfficeOnlyTypes.end()) + { + oOOFlavor.MimeType = aTryFlavor; + oOOFlavor.HumanPresentableName.clear(); + oOOFlavor.DataType = cppu::UnoType>::get(); + } + + return oOOFlavor; +} + +NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor, + bool& rbInternal) const +{ + NSString* sysFlavor = nullptr; + rbInternal = false; + + for (size_t i = 0; i < SIZE_FLAVOR_MAP; ++i) + { + if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor))) + { + sysFlavor = flavorMap[i].SystemFlavor; + } + } + + if (!sysFlavor) + { + // For some reason, if we allow text/html, we get an OSL_ENSURE failure in xmloff that + // apparently is a symptom of something being seriously wrong: + // xmloff/source/transform/OOo2Oasis.cxx:1925: duplicate doc handler + // Because is then followed a bit later by an assertion failure: + // Assertion failed: (!m_pFirst && !m_pLast && "There are still indices registered"), function ~SwIndexReg, file [...]/sw/source/core/bastyp/index.cxx, line 226 + + if (oOOFlavor.MimeType == "text/html") + return nil; + + rbInternal = true; + OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find(oOOFlavor.MimeType); + + if (it == maOfficeOnlyTypes.end()) + sysFlavor = maOfficeOnlyTypes[oOOFlavor.MimeType] + = OUStringToNSString(oOOFlavor.MimeType); + else + sysFlavor = it->second; + } + + return sysFlavor; +} + +NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(UIPasteboard* pPasteboard) +{ + if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PNG ]]) + return PBTYPE_PNG; + else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_JPEG ]]) + return PBTYPE_JPEG; + else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PDF ]]) + return PBTYPE_PDF; + return @""; +} + +DataProviderPtr_t +DataFlavorMapper::getDataProvider(const NSString* systemFlavor, + Reference const& rTransferable) const +{ + DataProviderPtr_t dp; + + try + { + DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor); + + Any data = rTransferable->getTransferData(oOOFlavor); + + if (isByteSequenceType(data.getValueType())) + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(data)); + } + else // Must be OUString type + { + SAL_WARN_IF(!isOUStringType(data.getValueType()), "vcl", "must be OUString type"); + 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, + NSData* systemData) +{ + DataProviderPtr_t dp; + + if ([systemFlavor caseInsensitiveCompare:PBTYPE_PLAINTEXT] == NSOrderedSame) + { + dp = DataProviderPtr_t(new UniDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare:PBTYPE_HTML] == NSOrderedSame) + { + dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData)); + } + else + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData)); + } + + return dp; +} + +bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const +{ + bool result = true; + + try + { + Reference xCntType(mrXMimeCntFactory->createMimeContentType(contentType)); + } + catch (IllegalArgumentException&) + { + result = false; + } + + return result; +} + +NSArray* DataFlavorMapper::flavorSequenceToTypesArray( + const css::uno::Sequence& flavors) const +{ + const sal_uInt32 nFlavors = flavors.getLength(); + NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:1]; + + bool bNeedDummyInternalFlavor(false); + + for (sal_uInt32 i = 0; i < nFlavors; i++) + { + if (flavors[i].MimeType.startsWith("image/bmp")) + { + [array addObject:PBTYPE_PNG]; + } + else + { + const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor); + + if (str != nil) + { + [str retain]; + [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 || bNeedDummyInternalFlavor) + { + [array addObject:PBTYPE_DUMMY_INTERNAL]; + } + + return [array autorelease]; +} + +css::uno::Sequence +DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const +{ + int nFormats = [types count]; + Sequence 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; + SAL_INFO("vcl.ios.clipboard", + "Mapped " << [sysFormat UTF8String] << " to " << oOOFlavor.MimeType); + } + } + + return flavors; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/DataFlavorMapping.hxx b/vcl/ios/DataFlavorMapping.hxx new file mode 100644 index 000000000..7e527dc09 --- /dev/null +++ b/vcl/ios/DataFlavorMapping.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX +#define INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX + +#include +#include +#include +#include + +#include +#import +#include + +#include +#include + +/* 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 css::uno::Any getOOoData() = 0; +}; + +typedef std::unique_ptr DataProviderPtr_t; + +class DataFlavorMapper +{ +public: + /* Initialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service + cannot be created. + */ + DataFlavorMapper(); + ~DataFlavorMapper(); + + /* Map a system data flavor to an OpenOffice data flavor. + Return an empty string if there is not suitable + mapping from a system data flavor to an OpenOffice data + flavor. + */ + css::datatransfer::DataFlavor systemToOpenOfficeFlavor(const NSString* systemDataFlavor) const; + + /* Map an OpenOffice data flavor to a system data flavor. + If there is no suitable mapping available NULL will + be returned. + */ + NSString* openOfficeToSystemFlavor(const css::datatransfer::DataFlavor& oooDataFlavor, + bool& rbInternal) const; + + /* Select the best available image data type + If there is no suitable mapping available NULL will + be returned. + */ + static NSString* openOfficeImageToSystemFlavor(UIPasteboard* pPasteboard); + + /* 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( + const NSString* systemFlavor, + const css::uno::Reference& rTransferable) const; + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + static DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSArray* systemData); + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + static DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSData* systemData); + + /* 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 css::uno::Sequence& 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. + */ + css::uno::Sequence + typesArrayToFlavorSequence(NSArray* types) const; + +private: + /* Determines if the provided Mime content type is valid. + */ + bool isValidMimeContentType(const OUString& contentType) const; + +private: + css::uno::Reference mrXMimeCntFactory; + typedef std::unordered_map OfficeOnlyTypes; + mutable OfficeOnlyTypes maOfficeOnlyTypes; +}; + +#endif // INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/HtmlFmtFlt.cxx b/vcl/ios/HtmlFmtFlt.cxx new file mode 100644 index 000000000..4f90ced3b --- /dev/null +++ b/vcl/ios/HtmlFmtFlt.cxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "HtmlFmtFlt.hxx" + +#include +#include + +#include +#include +#include +#include +#include + +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. Starting 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 +// and (no space between !-- and the +// text + +namespace +{ +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(); +} +} + +// the office always 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(""); +const std::string TAG_END_HTML = std::string(""); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. #92840# +const std::string TAG_BODY = std::string(" SAL_CALL TextHtmlToHTMLFormat(Sequence const& aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (aTextHtml.getLength() <= 0) + return Sequence(); + + // 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(aTextHtml.getConstArray()), + reinterpret_cast(aTextHtml.getConstArray()) + + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader + - 1; // we start one before '' 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 ? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. #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 byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + memset(byteSequence.getArray(), 0, byteSequence.getLength()); + + memcpy(static_cast(byteSequence.getArray()), + static_cast(htmlFormat.c_str()), htmlFormat.length()); + + return byteSequence; +} + +const char* const HtmlStartTag = " HTMLFormatToTextHtml(const Sequence& aHTMLFormat) +{ + assert(isHTMLFormat(aHTMLFormat) && "No HTML Format provided"); + + Sequence& nonconstHTMLFormatRef = const_cast&>(aHTMLFormat); + char* dataStart = reinterpret_cast(nonconstHTMLFormatRef.getArray()); + char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1; + const char* htmlStartTag = strcasestr(dataStart, HtmlStartTag); + + 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 == nullptr) + { + return aHTMLFormat; + } + + sal_Int32 len = dataEnd - htmlStartTag; + Sequence plainHtmlData(len); + + memcpy(static_cast(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 const HtmlFormatStartLen = (sizeof(HtmlFormatStart) - 1); + +bool isHTMLFormat(const Sequence& aHtmlSequence) +{ + if (aHtmlSequence.getLength() < HtmlFormatStartLen) + return false; + + return rtl_str_compareIgnoreAsciiCase_WithLength( + HtmlFormatStart, HtmlFormatStartLen, + reinterpret_cast(aHtmlSequence.getConstArray()), HtmlFormatStartLen) + == 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/HtmlFmtFlt.hxx b/vcl/ios/HtmlFmtFlt.hxx new file mode 100644 index 000000000..b11b19857 --- /dev/null +++ b/vcl/ios/HtmlFmtFlt.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_HTMLFMTFLT_HXX +#define INCLUDED_VCL_OSX_HTMLFMTFLT_HXX + +#include + +/* Transform plain HTML into the format expected by MS Office. + */ +css::uno::Sequence TextHtmlToHTMLFormat(css::uno::Sequence const& aTextHtml); + +/* Transform the MS Office HTML format into plain HTML. + */ +css::uno::Sequence HTMLFormatToTextHtml(const css::uno::Sequence& 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 css::uno::Sequence& aHtmlSequence); + +#endif // INCLUDED_VCL_OSX_HTMLFMTFLT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/clipboard.cxx b/vcl/ios/clipboard.cxx new file mode 100644 index 000000000..b60cda1be --- /dev/null +++ b/vcl/ios/clipboard.cxx @@ -0,0 +1,185 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ios/iosinst.hxx" + +#include "clipboard.hxx" + +#include "DataFlavorMapping.hxx" +#include "iOSTransferable.hxx" +#include +#include +#include +#include + +iOSClipboard::iOSClipboard() + : WeakComponentImplHelper(m_aMutex) +{ + auto xContext = comphelper::getProcessComponentContext(); + + mrXMimeCntFactory = css::datatransfer::MimeContentTypeFactory::create(xContext); + + mpDataFlavorMapper.reset(new DataFlavorMapper()); + + mPasteboard = [UIPasteboard generalPasteboard]; + assert(mPasteboard != nil); +} + +iOSClipboard::~iOSClipboard() {} + +css::uno::Reference SAL_CALL iOSClipboard::getContents() +{ + osl::MutexGuard aGuard(m_aMutex); + + return css::uno::Reference( + new iOSTransferable(mrXMimeCntFactory, mpDataFlavorMapper, mPasteboard)); +} + +void SAL_CALL iOSClipboard::setContents( + const css::uno::Reference& xTransferable, + const css::uno::Reference& /*xClipboardOwner*/) +{ + NSArray* types = xTransferable.is() ? mpDataFlavorMapper->flavorSequenceToTypesArray( + xTransferable->getTransferDataFlavors()) + : [NSArray array]; + + osl::ClearableMutexGuard aGuard(m_aMutex); + + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:1]; + NSArray* array = @[ dict ]; + + for (sal_uInt32 i = 0; i < [types count]; ++i) + { + DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(types[i], xTransferable); + + if (dp.get() != nullptr) + { + NSData* pBoardData = (NSData*)dp->getSystemData(); + dict[types[i]] = pBoardData; + } + } + [mPasteboard setItems:array options:@{}]; + + // We don't keep a copy of the clipboard contents around in-process, so fire the lost clipboard + // ownership event right away. + // fireLostClipboardOwnershipEvent(xClipboardOwner, xTransferable); + + // fireClipboardChangedEvent(xTransferable); +} + +OUString SAL_CALL iOSClipboard::getName() { return OUString(); } + +sal_Int8 SAL_CALL iOSClipboard::getRenderingCapabilities() { return 0; } + +void SAL_CALL iOSClipboard::addClipboardListener( + const css::uno::Reference& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw css::lang::IllegalArgumentException( + "empty reference", static_cast(this), 1); + + mClipboardListeners.push_back(listener); +} + +void SAL_CALL iOSClipboard::removeClipboardListener( + const css::uno::Reference& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw css::lang::IllegalArgumentException( + "empty reference", static_cast(this), 1); + + mClipboardListeners.remove(listener); +} + +void iOSClipboard::fireClipboardChangedEvent( + css::uno::Reference xNewContents) +{ + osl::ClearableMutexGuard aGuard(m_aMutex); + + std::list> listeners( + mClipboardListeners); + css::datatransfer::clipboard::ClipboardEvent aEvent; + + if (!listeners.empty()) + { + aEvent = css::datatransfer::clipboard::ClipboardEvent(static_cast(this), + xNewContents); + } + + aGuard.clear(); + + while (!listeners.empty()) + { + if (listeners.front().is()) + { + try + { + listeners.front()->changedContents(aEvent); + } + catch (const css::uno::RuntimeException&) + { + } + } + listeners.pop_front(); + } +} + +void iOSClipboard::fireLostClipboardOwnershipEvent( + css::uno::Reference const& oldOwner, + css::uno::Reference const& oldContent) +{ + assert(oldOwner.is()); + + try + { + oldOwner->lostOwnership(static_cast(this), + oldContent); + } + catch (const css::uno::RuntimeException&) + { + } +} + +OUString SAL_CALL iOSClipboard::getImplementationName() +{ + return OUString("com.sun.star.datatransfer.clipboard.iOSClipboard"); +} + +sal_Bool SAL_CALL iOSClipboard::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence SAL_CALL iOSClipboard::getSupportedServiceNames() +{ + return { OUString("com.sun.star.datatransfer.clipboard.SystemClipboard") }; +} + +css::uno::Reference +IosSalInstance::CreateClipboard(const css::uno::Sequence&) +{ + return css::uno::Reference( + static_cast(new iOSClipboard())); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/clipboard.hxx b/vcl/ios/clipboard.hxx new file mode 100644 index 000000000..144e9c3ac --- /dev/null +++ b/vcl/ios/clipboard.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IOS_CLIPBOARD_HXX +#define INCLUDED_VCL_IOS_CLIPBOARD_HXX + +#include "DataFlavorMapping.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#import +#include + +class iOSClipboard + : public ::cppu::BaseMutex, + public ::cppu::WeakComponentImplHelper +{ +public: + iOSClipboard(); + + virtual ~iOSClipboard() override; + iOSClipboard(const iOSClipboard&) = delete; + iOSClipboard& operator=(const iOSClipboard&) = delete; + + // XClipboard + + css::uno::Reference SAL_CALL getContents() override; + + void SAL_CALL setContents( + const css::uno::Reference& xTransferable, + const css::uno::Reference& xClipboardOwner) + override; + + OUString SAL_CALL getName() override; + + // XClipboardEx + + sal_Int8 SAL_CALL getRenderingCapabilities() override; + + // XClipboardNotifier + + void SAL_CALL addClipboardListener( + const css::uno::Reference& listener) + override; + + void SAL_CALL removeClipboardListener( + const css::uno::Reference& listener) + override; + + // XServiceInfo + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + +private: + /* Notify the current clipboard owner that he is no longer the clipboard owner. */ + void fireLostClipboardOwnershipEvent( + css::uno::Reference const& oldOwner, + css::uno::Reference const& oldContent); + + /* Notify all registered XClipboardListener that the clipboard content has changed. */ + void + fireClipboardChangedEvent(css::uno::Reference xNewContents); + +private: + css::uno::Reference mrXMimeCntFactory; + std::list> + mClipboardListeners; + css::uno::Reference mXClipboardOwner; + std::shared_ptr mpDataFlavorMapper; + UIPasteboard* mPasteboard; +}; + +#endif // INCLUDED_VCL_IOS_CLIPBOARD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/dummies.cxx b/vcl/ios/dummies.cxx new file mode 100644 index 000000000..d62609dc9 --- /dev/null +++ b/vcl/ios/dummies.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include +#include "salprn.hxx" +#include "quartz/salgdi.h" +#include "headless/svpinst.hxx" +#include "unx/fontmanager.hxx" +#include "unx/gendata.hxx" + +class FreetypeManager +{ +}; + +std::unique_ptr SvpSalInstance::CreatePrinter( SalInfoPrinter* /* pInfoPrinter */ ) +{ + return nullptr; +} + +OUString SvpSalInstance::GetDefaultPrinter() +{ + return OUString(); +} + +std::unique_ptr SvpSalInstance::CreatePrintGraphics() +{ + return nullptr; +} + +void SvpSalInstance::PostPrintersChanged() +{ +} + +SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* /* pQueueInfo */, + ImplJobSetup* /* pJobSetup */ ) +{ + return NULL; +} + +void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + delete pPrinter; +} + +void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* /* pList */ ) +{ +} + +void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* /* pInfo */ ) +{ +} + +std::unique_ptr SalGenericInstance::CreatePrinter( SalInfoPrinter* /* pInfoPrinter */ ) +{ + return nullptr; +} + +OUString SalGenericInstance::GetDefaultPrinter() +{ + return OUString(); +} + +void SalGenericInstance::PostPrintersChanged() +{ +} + +SalInfoPrinter* SalGenericInstance::CreateInfoPrinter( SalPrinterQueueInfo* /* pQueueInfo */, + ImplJobSetup* /* pJobSetup */ ) +{ + return NULL; +} + +void SalGenericInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + delete pPrinter; +} + +void SalGenericInstance::GetPrinterQueueInfo( ImplPrnQueueList* /* pList */ ) +{ +} + +void SalGenericInstance::GetPrinterQueueState( SalPrinterQueueInfo* /* pInfo */ ) +{ +} + +void SalGenericInstance::updatePrinterUpdate() +{ +} + +void SalGenericInstance::jobStartedPrinterUpdate() +{ +} + +void SalGenericInstance::jobEndedPrinterUpdate() +{ +} + +bool AquaSalGraphics::drawEPS( long, long, long, long, void*, sal_uInt32 ) +{ + return false; +} + +using namespace psp; + +GenericUnixSalData::GenericUnixSalData(GenericUnixSalDataType const t, SalInstance *const pInstance) + : m_eType(t) + , m_pDisplay(nullptr) + , m_pFreetypeManager(new FreetypeManager) + , m_pPrintFontManager(nullptr) +{ + m_pInstance = pInstance; + SetSalData(this); +} + +GenericUnixSalData::~GenericUnixSalData() +{ +} + +PrintFontManager::~PrintFontManager() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/iOSTransferable.cxx b/vcl/ios/iOSTransferable.cxx new file mode 100644 index 000000000..9ec27867f --- /dev/null +++ b/vcl/ios/iOSTransferable.cxx @@ -0,0 +1,186 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include "iOSTransferable.hxx" + +#include "DataFlavorMapping.hxx" + +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::lang; + +namespace +{ +bool isValidFlavor(const DataFlavor& aFlavor) +{ + size_t len = aFlavor.MimeType.getLength(); + Type dtype = aFlavor.DataType; + return ((len > 0) + && ((dtype == cppu::UnoType>::get()) + || (dtype == cppu::UnoType::get()))); +} + +bool cmpAllContentTypeParameter(const Reference& xLhs, + const Reference& xRhs) +{ + Sequence xLhsFlavors = xLhs->getParameters(); + Sequence 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; +} + +} // unnamed namespace + +iOSTransferable::iOSTransferable(const Reference& rXMimeCntFactory, + std::shared_ptr pDataFlavorMapper, + UIPasteboard* pasteboard) + : mrXMimeCntFactory(rXMimeCntFactory) + , mDataFlavorMapper(pDataFlavorMapper) + , mPasteboard(pasteboard) +{ + [mPasteboard retain]; + + initClipboardItemList(); +} + +iOSTransferable::~iOSTransferable() { [mPasteboard release]; } + +Any SAL_CALL iOSTransferable::getTransferData(const DataFlavor& aFlavor) +{ + if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor)) + { + throw UnsupportedFlavorException("Unsupported data flavor", + static_cast(this)); + } + + bool bInternal(false); + NSString* sysFormat = (aFlavor.MimeType.startsWith("image/png")) + ? DataFlavorMapper::openOfficeImageToSystemFlavor(mPasteboard) + : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor, bInternal); + DataProviderPtr_t dp; + + NSData* sysData = [mPasteboard dataForPasteboardType:sysFormat]; + dp = DataFlavorMapper::getDataProvider(sysFormat, sysData); + + if (dp.get() == nullptr) + { + throw UnsupportedFlavorException("Unsupported data flavor", + static_cast(this)); + } + + return dp->getOOoData(); +} + +Sequence SAL_CALL iOSTransferable::getTransferDataFlavors() { return mFlavorList; } + +sal_Bool SAL_CALL iOSTransferable::isDataFlavorSupported(const DataFlavor& aFlavor) +{ + for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++) + if (compareDataFlavors(aFlavor, mFlavorList[i])) + return true; + + return false; +} + +void iOSTransferable::initClipboardItemList() +{ + NSArray* pboardFormats = [mPasteboard pasteboardTypes]; + + if (pboardFormats == nullptr) + { + throw RuntimeException("Cannot get clipboard data", static_cast(this)); + } + +#ifdef SAL_LOG_INFO + NSString* types = @""; + for (unsigned i = 0; i < [pboardFormats count]; i++) + { + if ([types length] > 0) + types = [types stringByAppendingString:@", "]; + types = [types stringByAppendingString:[pboardFormats objectAtIndex:i]]; + } + SAL_INFO("vcl.ios.clipboard", "Types on clipboard: " << [types UTF8String]); +#endif + + 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 iOSTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs) +{ + try + { + Reference xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType)); + Reference xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType)); + + if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) + || !cmpAllContentTypeParameter(xLhs, xRhs)) + { + return false; + } + } + catch (IllegalArgumentException&) + { + OSL_FAIL("Invalid content type detected"); + return false; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/iOSTransferable.hxx b/vcl/ios/iOSTransferable.hxx new file mode 100644 index 000000000..5c685dba8 --- /dev/null +++ b/vcl/ios/iOSTransferable.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_IOS_IOSTRANSFERABLE_HXX +#define INCLUDED_VCL_IOS_IOSTRANSFERABLE_HXX + +#include +#include +#include +#include + +#include "DataFlavorMapping.hxx" + +#include +#import +#include + +#include +#include + +class iOSTransferable : public ::cppu::WeakImplHelper +{ +public: + explicit iOSTransferable( + css::uno::Reference const& rXMimeCntFactory, + std::shared_ptr pDataFlavorMapper, UIPasteboard* pasteboard); + + virtual ~iOSTransferable() override; + iOSTransferable(const iOSTransferable&) = delete; + iOSTransferable& operator=(const iOSTransferable&) = delete; + + // XTransferable + + virtual css::uno::Any SAL_CALL + getTransferData(const css::datatransfer::DataFlavor& aFlavor) override; + + css::uno::Sequence SAL_CALL getTransferDataFlavors() override; + + sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& aFlavor) override; + + // Helper functions not part of the XTransferable interface + + void initClipboardItemList(); + + bool compareDataFlavors(const css::datatransfer::DataFlavor& lhs, + const css::datatransfer::DataFlavor& rhs); + +private: + css::uno::Sequence mFlavorList; + css::uno::Reference mrXMimeCntFactory; + std::shared_ptr mDataFlavorMapper; + UIPasteboard* mPasteboard; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/iosinst.cxx b/vcl/ios/iosinst.cxx new file mode 100644 index 000000000..65963ef9c --- /dev/null +++ b/vcl/ios/iosinst.cxx @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include "ios/iosinst.hxx" +#include "headless/svpdummies.hxx" +#include "unx/gendata.hxx" +#include "quartz/utils.h" +#include +#include + +// Totally wrong of course but doesn't seem to harm much in the iOS app. +static int viewWidth = 1, viewHeight = 1; + +class IosSalData : public GenericUnixSalData +{ +public: + explicit IosSalData(SalInstance *pInstance) + : GenericUnixSalData(SAL_DATA_IOS, pInstance) + { + } + virtual void ErrorTrapPush() {} + virtual bool ErrorTrapPop( bool ) { return false; } +}; + +void IosSalInstance::GetWorkArea( tools::Rectangle& rRect ) +{ + rRect = tools::Rectangle( Point( 0, 0 ), + Size( viewWidth, viewHeight ) ); +} + +IosSalInstance *IosSalInstance::getInstance() +{ + if (!ImplGetSVData()) + return NULL; + IosSalData *pData = static_cast(ImplGetSVData()->mpSalData); + if (!pData) + return NULL; + return static_cast(pData->m_pInstance); +} + +IosSalInstance::IosSalInstance( std::unique_ptr pMutex ) + : SvpSalInstance( std::move(pMutex) ) +{ +} + +IosSalInstance::~IosSalInstance() +{ +} + +class IosSalSystem : public SvpSalSystem { +public: + IosSalSystem() : SvpSalSystem() {} + virtual ~IosSalSystem() {} + virtual int ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ); +}; + +SalSystem *IosSalInstance::CreateSalSystem() +{ + return new IosSalSystem(); +} + +class IosSalFrame : public SvpSalFrame +{ +public: + IosSalFrame( IosSalInstance *pInstance, + SalFrame *pParent, + SalFrameStyleFlags nSalFrameStyle) + : SvpSalFrame( pInstance, pParent, nSalFrameStyle ) + { + if (pParent == NULL && viewWidth > 1 && viewHeight > 1) + SetPosSize(0, 0, viewWidth, viewHeight, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); + } + + virtual void GetWorkArea( tools::Rectangle& rRect ) override + { + IosSalInstance::getInstance()->GetWorkArea( rRect ); + } + + virtual void ShowFullScreen( bool, sal_Int32 ) override + { + SetPosSize( 0, 0, viewWidth, viewHeight, + SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT ); + } + + virtual void UpdateSettings( AllSettings &rSettings ) override + { + // Clobber the UI fonts + vcl::Font aFont( "Helvetica", Size( 0, 10 ) ); + + StyleSettings aStyleSet = rSettings.GetStyleSettings(); + aStyleSet.SetAppFont( aFont ); + aStyleSet.SetHelpFont( aFont ); + aStyleSet.SetMenuFont( aFont ); + aStyleSet.SetToolFont( aFont ); + aStyleSet.SetLabelFont( aFont ); + aStyleSet.SetRadioCheckFont( aFont ); + aStyleSet.SetPushButtonFont( aFont ); + aStyleSet.SetFieldFont( aFont ); + aStyleSet.SetIconFont( aFont ); + aStyleSet.SetTabFont( aFont ); + aStyleSet.SetGroupFont( aFont ); + + Color aBackgroundColor( 0xff, 0xff, 0xff ); + aStyleSet.BatchSetBackgrounds( aBackgroundColor, false ); + aStyleSet.SetMenuColor( aBackgroundColor ); + aStyleSet.SetMenuBarColor( aBackgroundColor ); + aStyleSet.SetDialogColor( aBackgroundColor ); + + rSettings.SetStyleSettings( aStyleSet ); + } +}; + +SalFrame *IosSalInstance::CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle ) +{ + pParent = NULL; + return new IosSalFrame( this, NULL, nStyle ); +} + +SalFrame *IosSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle ) +{ + return new IosSalFrame( this, pParent, nStyle ); +} + +void SalAbort( const OUString& rErrorText, bool bDumpCore ) +{ + (void) bDumpCore; + + NSLog(@"SalAbort: %s", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() ); +} + +const OUString& SalGetDesktopEnvironment() +{ + static OUString aEnv( "iOS" ); + return aEnv; +} + +SalData::SalData() : + m_pInstance( 0 ), + mpFontList( 0 ), + mxRGBSpace( CGColorSpaceCreateDeviceRGB() ), + mxGraySpace( CGColorSpaceCreateDeviceGray() ) +{ +} + +SalData::~SalData() +{ +} + +// This is our main entry point: +SalInstance *CreateSalInstance() +{ + IosSalInstance* pInstance = new IosSalInstance( std::make_unique() ); + new IosSalData( pInstance ); + pInstance->AcquireYieldMutex(); + return pInstance; +} + +void DestroySalInstance( SalInstance *pInst ) +{ + pInst->ReleaseYieldMutexAll(); + delete pInst; +} + +int IosSalSystem::ShowNativeDialog( const OUString& rTitle, + const OUString& rMessage, + const std::vector< OUString >& rButtons ) +{ + (void)rButtons; + + NSLog(@"%@: %@", CreateNSString(rTitle), CreateNSString(rMessage)); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx new file mode 100644 index 000000000..759007ce4 --- /dev/null +++ b/vcl/jsdialog/jsdialogbuilder.cxx @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include + +void JSDialogSender::notifyDialogState() +{ + if (!m_aOwnedToplevel) + return; + + const vcl::ILibreOfficeKitNotifier* pNotifier = m_aOwnedToplevel->GetLOKNotifier(); + if (pNotifier) + { + std::stringstream aStream; + boost::property_tree::ptree aTree = m_aOwnedToplevel->DumpAsPropertyTree(); + aTree.put("id", m_aOwnedToplevel->GetLOKWindowId()); + boost::property_tree::write_json(aStream, aTree); + const std::string message = aStream.str(); + pNotifier->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG, message.c_str()); + } +} + +JSInstanceBuilder::JSInstanceBuilder(weld::Widget* pParent, const OUString& rUIRoot, + const OUString& rUIFile) + : SalInstanceBuilder(dynamic_cast(pParent) + ? dynamic_cast(pParent)->getWidget() + : nullptr, + rUIRoot, rUIFile) +{ +} + +std::unique_ptr JSInstanceBuilder::weld_dialog(const OString& id, bool bTakeOwnership) +{ + ::Dialog* pDialog = m_xBuilder->get<::Dialog>(id); + std::unique_ptr pRet(pDialog ? new SalInstanceDialog(pDialog, this, false) + : nullptr); + if (bTakeOwnership && pDialog) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pDialog); + m_xBuilder->drop_ownership(pDialog); + } + + const vcl::ILibreOfficeKitNotifier* pNotifier = pDialog->GetLOKNotifier(); + if (pNotifier) + { + std::stringstream aStream; + boost::property_tree::ptree aTree = m_aOwnedToplevel->DumpAsPropertyTree(); + aTree.put("id", m_aOwnedToplevel->GetLOKWindowId()); + boost::property_tree::write_json(aStream, aTree); + const std::string message = aStream.str(); + pNotifier->libreOfficeKitViewCallback(LOK_CALLBACK_JSDIALOG, message.c_str()); + } + + return pRet; +} + +std::unique_ptr JSInstanceBuilder::weld_label(const OString& id, bool bTakeOwnership) +{ + ::FixedText* pLabel = m_xBuilder->get(id); + return std::make_unique(m_aOwnedToplevel, pLabel, this, bTakeOwnership); +} + +std::unique_ptr JSInstanceBuilder::weld_button(const OString& id, bool bTakeOwnership) +{ + ::Button* pButton = m_xBuilder->get<::Button>(id); + return pButton ? std::make_unique(m_aOwnedToplevel, pButton, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr JSInstanceBuilder::weld_entry(const OString& id, bool bTakeOwnership) +{ + Edit* pEntry = m_xBuilder->get(id); + return pEntry ? std::make_unique(m_aOwnedToplevel, pEntry, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr JSInstanceBuilder::weld_combo_box(const OString& id, + bool bTakeOwnership) +{ + vcl::Window* pWidget = m_xBuilder->get(id); + ::ComboBox* pComboBox = dynamic_cast<::ComboBox*>(pWidget); + if (pComboBox) + return std::make_unique(m_aOwnedToplevel, pComboBox, this, bTakeOwnership); + ListBox* pListBox = dynamic_cast(pWidget); + return pListBox ? std::make_unique(m_aOwnedToplevel, pListBox, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr JSInstanceBuilder::weld_notebook(const OString& id, + bool bTakeOwnership) +{ + TabControl* pNotebook = m_xBuilder->get(id); + return pNotebook + ? std::make_unique(m_aOwnedToplevel, pNotebook, this, bTakeOwnership) + : nullptr; +} + +JSLabel::JSLabel(VclPtr aOwnedToplevel, FixedText* pLabel, + SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pLabel, pBuilder, bTakeOwnership) +{ +} + +void JSLabel::set_label(const OUString& rText) +{ + SalInstanceLabel::set_label(rText); + notifyDialogState(); +}; + +JSButton::JSButton(VclPtr aOwnedToplevel, ::Button* pButton, + SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pButton, pBuilder, bTakeOwnership) +{ +} + +JSEntry::JSEntry(VclPtr aOwnedToplevel, ::Edit* pEntry, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pEntry, pBuilder, bTakeOwnership) +{ +} + +void JSEntry::set_text(const OUString& rText) +{ + SalInstanceEntry::set_text(rText); + notifyDialogState(); +} + +JSListBox::JSListBox(VclPtr aOwnedToplevel, ::ListBox* pListBox, + SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pListBox, pBuilder, + bTakeOwnership) +{ +} + +void JSListBox::insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) +{ + SalInstanceComboBoxWithoutEdit::insert(pos, rStr, pId, pIconName, pImageSurface); + notifyDialogState(); +} + +void JSListBox::remove(int pos) +{ + SalInstanceComboBoxWithoutEdit::remove(pos); + notifyDialogState(); +} + +JSComboBox::JSComboBox(VclPtr aOwnedToplevel, ::ComboBox* pComboBox, + SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pComboBox, pBuilder, + bTakeOwnership) +{ +} + +void JSComboBox::insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) +{ + SalInstanceComboBoxWithEdit::insert(pos, rStr, pId, pIconName, pImageSurface); + notifyDialogState(); +} + +void JSComboBox::remove(int pos) +{ + SalInstanceComboBoxWithEdit::remove(pos); + notifyDialogState(); +} + +void JSComboBox::set_entry_text(const OUString& rText) +{ + SalInstanceComboBoxWithEdit::set_entry_text(rText); + notifyDialogState(); +} + +JSNotebook::JSNotebook(VclPtr aOwnedToplevel, ::TabControl* pControl, + SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : JSWidget(aOwnedToplevel, pControl, pBuilder, + bTakeOwnership) +{ +} + +void JSNotebook::set_current_page(int nPage) +{ + SalInstanceNotebook::set_current_page(nPage); + notifyDialogState(); +} + +void JSNotebook::set_current_page(const OString& rIdent) +{ + SalInstanceNotebook::set_current_page(rIdent); + notifyDialogState(); +} + +void JSNotebook::remove_page(const OString& rIdent) +{ + SalInstanceNotebook::remove_page(rIdent); + notifyDialogState(); +} + +void JSNotebook::insert_page(const OString& rIdent, const OUString& rLabel, int nPos) +{ + SalInstanceNotebook::insert_page(rIdent, rLabel, nPos); + notifyDialogState(); +} diff --git a/vcl/null/printerinfomanager.cxx b/vcl/null/printerinfomanager.cxx new file mode 100644 index 000000000..cfdb6eb67 --- /dev/null +++ b/vcl/null/printerinfomanager.cxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "printerinfomanager.hxx" + +#include "unx/gendata.hxx" + +// needed since we declare a std::unique_ptr +namespace psp +{ + class SystemQueueInfo + { + }; +} + +using namespace psp; +using namespace osl; + + +PrinterInfoManager& PrinterInfoManager::get() +{ + SalData* pSalData = GetSalData(); + if( ! pSalData->m_pPIManager ) + pSalData->m_pPIManager = new PrinterInfoManager(); + return *pSalData->m_pPIManager; +} + +void PrinterInfoManager::release() +{ + SalData* pSalData = GetSalData(); + delete pSalData->m_pPIManager; + pSalData->m_pPIManager = nullptr; +} + +PrinterInfoManager::PrinterInfoManager( Type eType ) : + m_pQueueInfo( nullptr ), + m_eType( eType ), + m_bUseIncludeFeature( false ), + m_bUseJobPatch( true ), + m_aSystemDefaultPaper( "A4" ) +{ + // initSystemDefaultPaper(); +} + +PrinterInfoManager::~PrinterInfoManager() +{ + +} + +bool PrinterInfoManager::checkPrintersChanged( bool /* bWait */ ) +{ + return false; +} + +void PrinterInfoManager::initialize() +{ + // ??? +} + +void PrinterInfoManager::listPrinters( ::std::vector< OUString >& rVector ) const +{ + (void) this; + + rVector.clear(); +} + +const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& /* rPrinter */ ) const +{ + static PrinterInfo aEmptyInfo; + + (void) this; + + return aEmptyInfo; +} + +bool PrinterInfoManager::checkFeatureToken( const OUString& /* rPrinterName */, const char* /* pToken */ ) const +{ + (void) this; + + return false; +} + +FILE* PrinterInfoManager::startSpool( const OUString& /* rPrintername */, bool /* bQuickCommand */ ) +{ + return nullptr; +} + +bool PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* /* pFile */, const JobData& /*rDocumentJobData*/, bool /*bBanner*/, const OUString& /*rFaxNumber*/ ) +{ + return true; +} + +void PrinterInfoManager::setupJobContextData( JobData& /* rData */ ) +{ + +} + +void PrinterInfoManager::setDefaultPaper( PPDContext& /* rContext */ ) const +{ + (void) this; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/DeviceInfo.cxx b/vcl/opengl/DeviceInfo.cxx new file mode 100644 index 000000000..24f42e34e --- /dev/null +++ b/vcl/opengl/DeviceInfo.cxx @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +OpenGLDeviceInfo::~OpenGLDeviceInfo() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/FixedTextureAtlas.cxx b/vcl/opengl/FixedTextureAtlas.cxx new file mode 100644 index 000000000..7425942d1 --- /dev/null +++ b/vcl/opengl/FixedTextureAtlas.cxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include + +struct FixedTexture +{ + std::shared_ptr mpTexture; + int mnFreeSlots; + std::vector maAllocatedSlots; + + FixedTexture(int nTextureWidth, int nTextureHeight, int nNumberOfSlots) + : mpTexture(std::make_shared(nTextureWidth, nTextureHeight, true)) + , mnFreeSlots(nNumberOfSlots) + , maAllocatedSlots(nNumberOfSlots, false) + { + auto aDeallocateFunction = [this] (int nSlotNumber) + { + deallocateSlot(nSlotNumber); + }; + + mpTexture->SetSlotDeallocateCallback(aDeallocateFunction); + mpTexture->InitializeSlotMechanism(nNumberOfSlots); + } + + ~FixedTexture() + { + mpTexture->ResetSlotDeallocateCallback(); + } + + void allocateSlot(int nSlot) + { + maAllocatedSlots[nSlot] = true; + mnFreeSlots--; + } + + void deallocateSlot(int nSlot) + { + maAllocatedSlots[nSlot] = false; + mnFreeSlots++; + } + + int findAndAllocateFreeSlot() + { + for (size_t i = 0; i < maAllocatedSlots.size(); ++i) + { + if (!maAllocatedSlots[i]) + { + allocateSlot(i); + return i; + } + } + return -1; + } + +private: + FixedTexture(const FixedTexture&) = delete; + FixedTexture& operator=(const FixedTexture&) = delete; +}; + +FixedTextureAtlasManager::FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nSubTextureSize) + : mWidthFactor(nWidthFactor) + , mHeightFactor(nHeightFactor) + , mSubTextureSize(nSubTextureSize) +{ +} + +FixedTextureAtlasManager::~FixedTextureAtlasManager() +{ +} + +void FixedTextureAtlasManager::CreateNewTexture() +{ + int nTextureWidth = mWidthFactor * mSubTextureSize; + int nTextureHeight = mHeightFactor * mSubTextureSize; + maFixedTextures.push_back(std::make_unique(nTextureWidth, nTextureHeight, mWidthFactor * mHeightFactor)); +} + +OpenGLTexture FixedTextureAtlasManager::Reserve(int nWidth, int nHeight) +{ + FixedTexture* pFixedTexture = nullptr; + + auto funFreeSlot = [] (std::unique_ptr& inFixedTexture) + { + return inFixedTexture->mnFreeSlots > 0; + }; + + auto it = std::find_if(maFixedTextures.begin(), maFixedTextures.end(), funFreeSlot); + + if (it != maFixedTextures.end()) + { + pFixedTexture = (*it).get(); + } + else + { + CreateNewTexture(); + pFixedTexture = maFixedTextures.back().get(); + } + + int nSlot = pFixedTexture->findAndAllocateFreeSlot(); + + // Calculate coordinates in texture + int nX = (nSlot % mWidthFactor) * mSubTextureSize; + int nY = (nSlot / mWidthFactor) * mSubTextureSize; + + tools::Rectangle aRectangle(Point(nX, nY), Size(nWidth, nHeight)); + + return OpenGLTexture(pFixedTexture->mpTexture, aRectangle, nSlot); +} + +OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData) +{ + OpenGLTexture aTexture = Reserve(nWidth, nHeight); + if (pData == nullptr) + return aTexture; + + aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData); + + return aTexture; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/LineRenderUtils.cxx b/vcl/opengl/LineRenderUtils.cxx new file mode 100644 index 000000000..e130fb93b --- /dev/null +++ b/vcl/opengl/LineRenderUtils.cxx @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include + +namespace vcl +{ + +LineBuilder::LineBuilder(std::vector& rVertices, std::vector& rIndices, + Color nColor, GLfloat fTransparency, + GLfloat fLineWidth, bool bUseAA) + : mrVertices(rVertices) + , mrIndices(rIndices) + , mR(nColor.GetRed()) + , mG(nColor.GetGreen()) + , mB(nColor.GetBlue()) + , mA((1.0f - fTransparency) * 255.0f) + , mfLineWidth(fLineWidth) + , mfLineWidthAndAA(bUseAA ? fLineWidth : -fLineWidth) + , mnInitialIndexSize(rIndices.size()) + , mbIncomplete(false) +{ +} + +void LineBuilder::appendLineSegment(const glm::vec2& rPoint1, const glm::vec2& rNormal1, GLfloat aExtrusion1, + const glm::vec2& rPoint2, const glm::vec2& rNormal2, GLfloat aExtrusion2) +{ + GLuint zero = mrVertices.size(); + + mrVertices.insert(mrVertices.end(), { + {rPoint1, glm::vec4{mR, mG, mB, mA}, glm::vec4{-rNormal1.x, -rNormal1.y, -aExtrusion1, mfLineWidthAndAA}}, + {rPoint1, glm::vec4{mR, mG, mB, mA}, glm::vec4{ rNormal1.x, rNormal1.y, aExtrusion1, mfLineWidthAndAA}}, + {rPoint2, glm::vec4{mR, mG, mB, mA}, glm::vec4{-rNormal2.x, -rNormal2.y, -aExtrusion2, mfLineWidthAndAA}}, + {rPoint2, glm::vec4{mR, mG, mB, mA}, glm::vec4{ rNormal2.x, rNormal2.y, aExtrusion2, mfLineWidthAndAA}}, + }); + + mrIndices.insert(mrIndices.end(), { + zero + 0, zero + 1, zero + 2, + zero + 2, zero + 1, zero + 3 + }); + +} + +void LineBuilder::appendLine(const glm::vec2& rPoint1, const glm::vec2& rPoint2) +{ + glm::vec2 aLineVector = vcl::vertex::normalize(rPoint2 - rPoint1); + glm::vec2 aNormal = vcl::vertex::perpendicular(aLineVector); + + appendLineSegment(rPoint1, aNormal, 1.0f, + rPoint2, aNormal, 1.0f); +} + +void LineBuilder::appendAndConnectLinePoint(const glm::vec2& rPoint, const glm::vec2& aNormal, GLfloat aExtrusion) +{ + GLuint zero = mrVertices.size(); + + mrVertices.insert(mrVertices.end(), { + {rPoint, glm::vec4{mR, mG, mB, mA}, glm::vec4{-aNormal.x, -aNormal.y, -aExtrusion, mfLineWidthAndAA}}, + {rPoint, glm::vec4{mR, mG, mB, mA}, glm::vec4{ aNormal.x, aNormal.y, aExtrusion, mfLineWidthAndAA}}, + }); + + if (mnInitialIndexSize == mrIndices.size()) + { + mrIndices.insert(mrIndices.end(), { + zero + 0, zero + 1 + }); + mbIncomplete = true; + } + else + { + if (mbIncomplete) + { + mrIndices.insert(mrIndices.end(), { + zero + 0, + zero + 0, zero - 1, zero + 1 + }); + mbIncomplete = false; + } + else + { + mrIndices.insert(mrIndices.end(), { + zero - 2, zero - 1, zero + 0, + zero + 0, zero - 1, zero + 1 + }); + } + } +} + +void LineBuilder::appendMiterJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + glm::vec2 const& nextLineVector) +{ + // With miter join we calculate the extrusion vector by adding normals of + // previous and next line segment. The vector shows the way but we also + // need the length (otherwise the line will be deformed). Length factor is + // calculated as dot product of extrusion vector and one of the normals. + // The value we get is the inverse length (used in the shader): + // length = line_width / dot(extrusionVector, normal) + + glm::vec2 normal(-prevLineVector.y, prevLineVector.x); + + glm::vec2 tangent = vcl::vertex::normalize(nextLineVector + prevLineVector); + glm::vec2 extrusionVector(-tangent.y, tangent.x); + GLfloat length = glm::dot(extrusionVector, normal); + + appendAndConnectLinePoint(point, extrusionVector, length); +} + +void LineBuilder::appendBevelJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + const glm::vec2& nextLineVector) +{ + // For bevel join we just add 2 additional vertices and use previous + // line segment normal and next line segment normal as extrusion vector. + // All the magic is done by the fact that we draw triangle strips, so we + // cover the joins correctly. + + glm::vec2 prevNormal(-prevLineVector.y, prevLineVector.x); + glm::vec2 nextNormal(-nextLineVector.y, nextLineVector.x); + + appendAndConnectLinePoint(point, prevNormal, 1.0f); + appendAndConnectLinePoint(point, nextNormal, 1.0f); +} + +void LineBuilder::appendRoundJoint(glm::vec2 const& point, const glm::vec2& prevLineVector, + const glm::vec2& nextLineVector) +{ + // For round join we do a similar thing as in bevel, we add more intermediate + // vertices and add normals to get extrusion vectors in the between the + // both normals. + + // 3 additional extrusion vectors + normals are enough to make most + // line joins look round. Ideally the number of vectors could be + // calculated. + + glm::vec2 prevNormal(-prevLineVector.y, prevLineVector.x); + glm::vec2 nextNormal(-nextLineVector.y, nextLineVector.x); + + glm::vec2 middle = vcl::vertex::normalize(prevNormal + nextNormal); + glm::vec2 middleLeft = vcl::vertex::normalize(prevNormal + middle); + glm::vec2 middleRight = vcl::vertex::normalize(middle + nextNormal); + + appendAndConnectLinePoint(point, prevNormal, 1.0f); + appendAndConnectLinePoint(point, middleLeft, 1.0f); + appendAndConnectLinePoint(point, middle, 1.0f); + appendAndConnectLinePoint(point, middleRight, 1.0f); + appendAndConnectLinePoint(point, nextNormal, 1.0f); +} + +void LineBuilder::appendRoundLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2) +{ + constexpr int nRoundCapIteration = 12; + + glm::vec2 lineVector = vcl::vertex::normalize(rPoint2 - rPoint1); + glm::vec2 normal(-lineVector.y, lineVector.x); + glm::vec2 previousRoundNormal = normal; + + for (int nFactor = 1; nFactor <= nRoundCapIteration; nFactor++) + { + float angle = float(nFactor) * (M_PI / float(nRoundCapIteration)); + glm::vec2 roundNormal(normal.x * glm::cos(angle) - normal.y * glm::sin(angle), + normal.x * glm::sin(angle) + normal.y * glm::cos(angle)); + + appendLineSegment(rPoint1, previousRoundNormal, 1.0f, + rPoint1, roundNormal, 1.0f); + previousRoundNormal = roundNormal; + } +} + +void LineBuilder::appendSquareLineCapVertices(const glm::vec2& rPoint1, const glm::vec2& rPoint2) +{ + glm::vec2 lineVector = vcl::vertex::normalize(rPoint2 - rPoint1); + glm::vec2 normal(-lineVector.y, lineVector.x); + + glm::vec2 extrudedPoint = rPoint1 + -lineVector * (mfLineWidth / 2.0f); + + appendLineSegment(extrudedPoint, normal, 1.0f, + rPoint1, normal, 1.0f); +} + +} // end vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/PackedTextureAtlas.cxx b/vcl/opengl/PackedTextureAtlas.cxx new file mode 100644 index 000000000..8508bbe3c --- /dev/null +++ b/vcl/opengl/PackedTextureAtlas.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include + +namespace { + +struct Node +{ + tools::Rectangle mRectangle; + std::unique_ptr mLeftNode; + std::unique_ptr mRightNode; + bool mOccupied; + + explicit Node(int nWidth, int nHeight); + explicit Node(tools::Rectangle const & aRectangle); + + bool isLeaf() const; + Node* insert(int nWidth, int nHeight, int nPadding); +}; + +} + +Node::Node(int nWidth, int nHeight) + : mRectangle(tools::Rectangle(Point(), Size(nWidth, nHeight))) + , mLeftNode() + , mRightNode() + , mOccupied(false) +{} + +Node::Node(tools::Rectangle const & aRectangle) + : mRectangle(aRectangle) + , mLeftNode() + , mRightNode() + , mOccupied(false) +{} + +bool Node::isLeaf() const { return mLeftNode == nullptr && mRightNode == nullptr; } + +Node* Node::insert(int nWidth, int nHeight, int nPadding) +{ + if (!isLeaf()) + { + Node* pNewNode = mLeftNode->insert(nWidth, nHeight, nPadding); + + if (pNewNode != nullptr) + return pNewNode; + + return mRightNode->insert(nWidth, nHeight, nPadding); + } + else + { + if (mOccupied) + { + return nullptr; + } + + if (nWidth > mRectangle.GetWidth() || nHeight > mRectangle.GetHeight()) + { // does not fit + return nullptr; + } + + if (nWidth == mRectangle.GetWidth() && nHeight == mRectangle.GetHeight()) + { // perfect fit + mOccupied = true; + return this; + } + + int dw = mRectangle.GetWidth() - nWidth; + int dh = mRectangle.GetHeight() - nHeight; + + tools::Rectangle aLeftRect; + tools::Rectangle aRightRect; + if (dw > dh) + { + aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()), + Size(nWidth, mRectangle.GetHeight())); + aRightRect = tools::Rectangle(Point(nPadding + mRectangle.Left() + nWidth, mRectangle.Top()), + Size(mRectangle.GetWidth() - nWidth - nPadding, mRectangle.GetHeight())); + } + else + { + aLeftRect = tools::Rectangle(Point(mRectangle.Left(), mRectangle.Top()), + Size(mRectangle.GetWidth(), nHeight)); + aRightRect = tools::Rectangle(Point(mRectangle.Left(), nPadding + mRectangle.Top() + nHeight), + Size(mRectangle.GetWidth(), mRectangle.GetHeight() - nHeight - nPadding)); + } + + mLeftNode.reset(new Node(aLeftRect)); + mRightNode.reset(new Node(aRightRect)); + + return mLeftNode->insert(nWidth, nHeight, nPadding); + } +} + +struct PackedTexture +{ + std::shared_ptr mpTexture; + std::unique_ptr mpRootNode; + + PackedTexture(int nWidth, int nHeight) + : mpTexture(std::make_shared(nWidth, nHeight, true)) + , mpRootNode(new Node(nWidth, nHeight)) + {} +}; + +PackedTextureAtlasManager::PackedTextureAtlasManager(int nTextureWidth, int nTextureHeight) + : mnTextureWidth(nTextureWidth) + , mnTextureHeight(nTextureHeight) +{ +} + +PackedTextureAtlasManager::~PackedTextureAtlasManager() +{ + for (std::unique_ptr& pPackedTexture : maPackedTextures) + { + // Free texture early in VCL shutdown while we have a context. + pPackedTexture->mpTexture.reset(); + } +} + +void PackedTextureAtlasManager::CreateNewTexture() +{ + std::unique_ptr pPackedTexture(new PackedTexture(mnTextureWidth, mnTextureHeight)); + GLuint nTextureID = pPackedTexture->mpTexture->mnTexture; + maPackedTextures.push_back(std::move(pPackedTexture)); + VCL_GL_INFO("PackedTextureAtlas::CreateNewTexture adding texture: " << nTextureID << + " atlases: " << maPackedTextures.size()); +} + +OpenGLTexture PackedTextureAtlasManager::Reserve(int nWidth, int nHeight) +{ + for (std::unique_ptr& pPackedTexture : maPackedTextures) + { + Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1); + if (pNode != nullptr) + { + return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1); + } + } + CreateNewTexture(); + std::unique_ptr& pPackedTexture = maPackedTextures.back(); + Node* pNode = pPackedTexture->mpRootNode->insert(nWidth, nHeight, 1); + if (pNode != nullptr) + { + return OpenGLTexture(pPackedTexture->mpTexture, pNode->mRectangle, -1); + } + return OpenGLTexture(); +} + +OpenGLTexture PackedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData) +{ + OpenGLTexture aTexture = Reserve(nWidth, nHeight); + if (aTexture && pData == nullptr) + return aTexture; + + aTexture.CopyData(nWidth, nHeight, nFormat, nType, pData); + + return aTexture; +} + +std::vector PackedTextureAtlasManager::ReduceTextureNumber(int nMaxNumberOfTextures) +{ + std::vector aTextureIDs; + while (int(maPackedTextures.size()) > nMaxNumberOfTextures) + { + // Remove oldest created texture + GLuint nTextureID = maPackedTextures[0]->mpTexture->mnTexture; + aTextureIDs.push_back(nTextureID); + maPackedTextures.erase(maPackedTextures.begin()); + VCL_GL_INFO("PackedTextureAtlas::ReduceTextureNumber removing texture: " << nTextureID << + " atlases: " << maPackedTextures.size()); + } + return aTextureIDs; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/README.deprecated b/vcl/opengl/README.deprecated new file mode 100644 index 000000000..eb033a0fd --- /dev/null +++ b/vcl/opengl/README.deprecated @@ -0,0 +1,23 @@ +deprecated features + +GL_LIGHTING +GL_TEXTURE_2D +GL_POINT_SMOOTH +GL_TEXTURE_WRAP_S +GL_TEXTURE_WRAP_T +glBegin +glEnd + + +GLSL + +texture*D +varying +attribute +missing version string + +gl_FragColor +gl_FragData +gl_Normal +gl_NormalMatrix +gl_Vertex diff --git a/vcl/opengl/README.opengl b/vcl/opengl/README.opengl new file mode 100644 index 000000000..231abbf36 --- /dev/null +++ b/vcl/opengl/README.opengl @@ -0,0 +1,26 @@ +Run LO with OpenGL enabled +-------------------------- +SAL_USE_VCLPLUGIN=gen SAL_FORCEGL=1 ./soffice + +Environment variables used: + +SAL_USE_VCLPLUGIN - use the specified VCL plugin (GTK2 in this case - currently +needed on Linux because the default GTK3 doesn't support OpenGL yet) + +SAL_FORCEGL - enable OpenGL even if the card is blacklisted. + +Other variables: + +LIBGL_ALWAYS_SOFTWARE=1 - on Linux+Mesa forces the software renderer to be used +(this is useful as an alternative to spot driver specific bugs) + +SAL_LOG=+INFO.vcl.opengl - if "--enable-dbgutil" is used, this can show OpenGL +various rendering messages. + +LD_PRELOAD=/usr/lib64/apitrace/wrappers/glxtrace.so - preload the wrapper for +APItrace. The path is the default used in Fedora 21+. + +Run VCLDemo +----------- + +SAL_USE_VCLPLUGIN=gen SAL_FORCEGL=1 ./bin/run vcldemo diff --git a/vcl/opengl/RenderList.cxx b/vcl/opengl/RenderList.cxx new file mode 100644 index 000000000..4830f1040 --- /dev/null +++ b/vcl/opengl/RenderList.cxx @@ -0,0 +1,403 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include + +#include +#include +#include +#include + +namespace +{ + +/** Append vertices for the polyline + * + * OpenGL polyline drawing algorithm inspired by: + * - http://mattdesl.svbtle.com/drawing-lines-is-hard + * - https://www.mapbox.com/blog/drawing-antialiased-lines/ + * - https://cesiumjs.org/2013/04/22/Robust-Polyline-Rendering-with-WebGL/ + * - http://artgrammer.blogspot.si/2011/05/drawing-nearly-perfect-2d-line-segments.html + * - http://artgrammer.blogspot.si/2011/07/drawing-polylines-by-tessellation.html + * + */ +void appendPolyLine(vcl::LineBuilder& rBuilder, const basegfx::B2DPolygon& rPolygon, + basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle) +{ + sal_uInt32 nPoints = rPolygon.count(); + bool bClosed = rPolygon.isClosed(); + + if (nPoints == 2 || eLineJoin == basegfx::B2DLineJoin::NONE) + { + // If line joint is NONE or a simple line with 2 points, draw the polyline + // each line segment separately. + + for (sal_uInt32 i = 0; i < (bClosed ? nPoints : nPoints - 1); ++i) + { + sal_uInt32 index1 = (i + 0) % nPoints; // loop indices - important when polyline is closed + sal_uInt32 index2 = (i + 1) % nPoints; + + glm::vec2 aPoint1(rPolygon.getB2DPoint(index1).getX(), rPolygon.getB2DPoint(index1).getY()); + glm::vec2 aPoint2(rPolygon.getB2DPoint(index2).getX(), rPolygon.getB2DPoint(index2).getY()); + + rBuilder.appendLine(aPoint1, aPoint2); + } + } + else if (nPoints > 2) + { + int i = 0; + int lastPoint = int(nPoints); + + glm::vec2 p0(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY()); + glm::vec2 p1(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY()); + glm::vec2 p2(rPolygon.getB2DPoint(1).getX(), rPolygon.getB2DPoint(1).getY()); + + glm::vec2 nextLineVector; + glm::vec2 previousLineVector; + glm::vec2 normal; // perpendicular to the line vector + + nextLineVector = vcl::vertex::normalize(p2 - p1); + + if (!bClosed) + { + normal = glm::vec2(-nextLineVector.y, nextLineVector.x); // make perpendicular + rBuilder.appendAndConnectLinePoint(p1, normal, 1.0f); + + i++; // first point done already + lastPoint--; // last point will be calculated separately from the loop + + p0 = p1; + previousLineVector = nextLineVector; + } + else + { + lastPoint++; // we need to connect last point to first point so one more line segment to calculate + previousLineVector = vcl::vertex::normalize(p1 - p0); + } + + for (; i < lastPoint; ++i) + { + int index1 = (i + 0) % nPoints; // loop indices - important when polyline is closed + int index2 = (i + 1) % nPoints; + + p1 = glm::vec2(rPolygon.getB2DPoint(index1).getX(), rPolygon.getB2DPoint(index1).getY()); + p2 = glm::vec2(rPolygon.getB2DPoint(index2).getX(), rPolygon.getB2DPoint(index2).getY()); + + if (p1 == p2) // skip equal points, normals could div-by-0 + continue; + + nextLineVector = vcl::vertex::normalize(p2 - p1); + + if (eLineJoin == basegfx::B2DLineJoin::Miter) + { + if (vcl::vertex::lineVectorAngle(previousLineVector, nextLineVector) < fMiterMinimumAngle) + rBuilder.appendBevelJoint(p1, previousLineVector, nextLineVector); + else + rBuilder.appendMiterJoint(p1, previousLineVector, nextLineVector); + } + else if (eLineJoin == basegfx::B2DLineJoin::Bevel) + { + rBuilder.appendBevelJoint(p1, previousLineVector, nextLineVector); + } + else if (eLineJoin == basegfx::B2DLineJoin::Round) + { + rBuilder.appendRoundJoint(p1, previousLineVector, nextLineVector); + } + p0 = p1; + previousLineVector = nextLineVector; + } + + if (!bClosed) + { + // Create vertices for the last point. There is no line join so just + // use the last line segment normal as the extrusion vector. + p1 = glm::vec2(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY()); + normal = glm::vec2(-previousLineVector.y, previousLineVector.x); + rBuilder.appendAndConnectLinePoint(p1, normal, 1.0f); + } + } + + if (!bClosed && nPoints >= 2 && (eLineCap == css::drawing::LineCap_ROUND || eLineCap == css::drawing::LineCap_SQUARE)) + { + glm::vec2 aBeginCapPoint1(rPolygon.getB2DPoint(0).getX(), rPolygon.getB2DPoint(0).getY()); + glm::vec2 aBeginCapPoint2(rPolygon.getB2DPoint(1).getX(), rPolygon.getB2DPoint(1).getY()); + + glm::vec2 aEndCapPoint1(rPolygon.getB2DPoint(nPoints - 1).getX(), rPolygon.getB2DPoint(nPoints - 1).getY()); + glm::vec2 aEndCapPoint2(rPolygon.getB2DPoint(nPoints - 2).getX(), rPolygon.getB2DPoint(nPoints - 2).getY()); + + if (eLineCap == css::drawing::LineCap_ROUND) + { + rBuilder.appendRoundLineCapVertices(aBeginCapPoint1, aBeginCapPoint2); + rBuilder.appendRoundLineCapVertices(aEndCapPoint1, aEndCapPoint2); + } + else if (eLineCap == css::drawing::LineCap_SQUARE) + { + rBuilder.appendSquareLineCapVertices(aBeginCapPoint1, aBeginCapPoint2); + rBuilder.appendSquareLineCapVertices(aEndCapPoint1, aEndCapPoint2); + } + } +} + +void appendTrapezoid(std::vector& rVertices, std::vector& rIndices, + GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, + GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4, + Color nColor, GLfloat fTransparency) +{ + GLubyte nR, nG, nB, nA; + vcl::vertex::createColor(nColor, fTransparency, nR, nG, nB, nA); + + GLuint zero = rVertices.size(); + + rVertices.insert(rVertices.end(), { + {glm::vec2{x1, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x2, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x3, y3}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x4, y4}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + }); + + rIndices.insert(rIndices.end(), { + zero + 0, zero + 1, zero + 2, + zero + 2, zero + 1, zero + 3 + }); +} + +void appendRectangle(std::vector& rVertices, std::vector& rIndices, + GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, + Color nColor, GLfloat fTransparency) +{ + GLubyte nR, nG, nB, nA; + vcl::vertex::createColor(nColor, fTransparency, nR, nG, nB, nA); + + GLuint zero = rVertices.size(); + + rVertices.insert(rVertices.end(), { + {glm::vec2{x1, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x2, y1}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x1, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + {glm::vec2{x2, y2}, glm::vec4{nR, nG, nB, nA}, glm::vec4{0.0f, 0.0f, 0.0f, 0.0f}}, + }); + + rIndices.insert(rIndices.end(), { + zero + 0, zero + 1, zero + 2, + zero + 2, zero + 1, zero + 3 + }); +} + +} // end anonymous namespace + +void RenderList::addDrawPixel(long nX, long nY, Color nColor) +{ + if (nColor == SALCOLOR_NONE) + return; + + checkOverlapping(basegfx::B2DRange(nX, nY, nX, nY)); + + RenderParameters& rRenderParameter = maRenderEntries.back().maTriangleParameters; + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + nX - 0.5f, nY - 0.5f, nX + 0.5f, nY + 0.5f, nColor, 0.0f); +} + +void RenderList::addDrawRectangle(long nX, long nY, long nWidth, long nHeight, double fTransparency, + Color nLineColor, Color nFillColor) +{ + if (nLineColor == SALCOLOR_NONE && nFillColor == SALCOLOR_NONE) + return; + if (fTransparency == 1.0f) + return; + + GLfloat fX1(nX); + GLfloat fY1(nY); + GLfloat fX2(nX + nWidth - 1); + GLfloat fY2(nY + nHeight - 1); + + checkOverlapping(basegfx::B2DRange(fX1, fY1, fX2, fY2)); + + RenderParameters& rRenderParameter = maRenderEntries.back().maTriangleParameters; + + // Draw rectangle stroke with line color + if (nLineColor != SALCOLOR_NONE) + { + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f, nLineColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nLineColor, fTransparency); + } + + if (nFillColor != SALCOLOR_NONE) + { + if (nLineColor == SALCOLOR_NONE) + { + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY1 - 0.5f, fX1 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY1 + 0.5f, nFillColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX2 - 0.5f, fY1 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency); + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 - 0.5f, fY2 - 0.5f, fX2 + 0.5f, fY2 + 0.5f, nFillColor, fTransparency); + } + // Draw rectangle fill with fill color + appendRectangle(rRenderParameter.maVertices, rRenderParameter.maIndices, + fX1 + 0.5f, fY1 + 0.5f, fX2 - 0.5f, fY2 - 0.5f, nFillColor, fTransparency); + } +} + +void RenderList::addDrawLine(long nX1, long nY1, long nX2, long nY2, Color nLineColor, bool bUseAA) +{ + if (nLineColor == SALCOLOR_NONE) + return; + + checkOverlapping(basegfx::B2DRange(nX1, nY1, nX2, nY2)); + + RenderParameters& rRenderParameter = maRenderEntries.back().maLineParameters; + + glm::vec2 aPoint1(nX1, nY1); + glm::vec2 aPoint2(nX2, nY2); + + vcl::LineBuilder aBuilder(rRenderParameter.maVertices, rRenderParameter.maIndices, nLineColor, 0.0f, 1.0f, bUseAA); + aBuilder.appendLine(aPoint1, aPoint2); +} + +void RenderList::addDrawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency, + Color nLineColor, Color nFillColor, bool bUseAA) +{ + if (rPolyPolygon.count() <= 0) + return; + if (nLineColor == SALCOLOR_NONE && nFillColor == SALCOLOR_NONE) + return; + if (fTransparency == 1.0) + return; + + checkOverlapping(rPolyPolygon.getB2DRange()); + + if (nFillColor != SALCOLOR_NONE) + { + basegfx::B2DTrapezoidVector aTrapezoidVector; + basegfx::utils::trapezoidSubdivide(aTrapezoidVector, rPolyPolygon); + + if (!aTrapezoidVector.empty()) + { + RenderParameters& rTriangleRenderParameter = maRenderEntries.back().maTriangleParameters; + + for (const basegfx::B2DTrapezoid & rTrapezoid : aTrapezoidVector) + { + GLfloat topX1 = rTrapezoid.getTopXLeft(); + GLfloat topX2 = rTrapezoid.getTopXRight(); + GLfloat topY = rTrapezoid.getTopY(); + + GLfloat bottomX1 = rTrapezoid.getBottomXLeft(); + GLfloat bottomX2 = rTrapezoid.getBottomXRight(); + GLfloat bottomY = rTrapezoid.getBottomY(); + + appendTrapezoid(rTriangleRenderParameter.maVertices, rTriangleRenderParameter.maIndices, + topX1, topY, topX2, topY, + bottomX1, bottomY, bottomX2, bottomY, + nFillColor, fTransparency); + } + } + } + + if (nLineColor != SALCOLOR_NONE || bUseAA) + { + RenderParameters& rLineRenderParameter = maRenderEntries.back().maLineParameters; + Color nColor = (nLineColor == SALCOLOR_NONE) ? nFillColor : nLineColor; + + vcl::LineBuilder aBuilder(rLineRenderParameter.maVertices, rLineRenderParameter.maIndices, + nColor, fTransparency, 1.0f, bUseAA); + + for (const basegfx::B2DPolygon& rPolygon : rPolyPolygon) + { + basegfx::B2DPolygon aPolygon(rPolygon); + if (rPolygon.areControlPointsUsed()) + aPolygon = rPolygon.getDefaultAdaptiveSubdivision(); + + sal_uInt32 nPoints = aPolygon.count(); + if (nPoints <= 1) + continue; + + GLfloat x1, y1, x2, y2; + sal_uInt32 index1, index2; + + for (sal_uInt32 i = 0; i <= nPoints; ++i) + { + index1 = i % nPoints; + index2 = (i + 1) % nPoints; + + x1 = aPolygon.getB2DPoint(index1).getX(); + y1 = aPolygon.getB2DPoint(index1).getY(); + x2 = aPolygon.getB2DPoint(index2).getX(); + y2 = aPolygon.getB2DPoint(index2).getY(); + + aBuilder.appendLine(glm::vec2(x1, y1), glm::vec2(x2, y2)); + } + } + } +} + +void RenderList::addDrawTextureWithMaskColor(OpenGLTexture const & rTexture, Color nColor, const SalTwoRect& r2Rect) +{ + if (!rTexture) + return; + + GLfloat fX1 = r2Rect.mnDestX; + GLfloat fY1 = r2Rect.mnDestY; + GLfloat fX2 = fX1 + r2Rect.mnDestWidth; + GLfloat fY2 = fY1 + r2Rect.mnDestHeight; + + checkOverlapping(basegfx::B2DRange(fX1, fY1, fX2, fY2)); + + GLuint nTextureId = rTexture.Id(); + + RenderTextureParameters& rTextureParameter = maRenderEntries.back().maTextureParametersMap[nTextureId]; + rTextureParameter.maTexture = rTexture; + + rTexture.FillCoords(rTextureParameter.maTextureCoords, r2Rect); + + vcl::vertex::addRectangle(rTextureParameter.maVertices, fX1, fY1, fX2, fY2); + vcl::vertex::addQuadColors(rTextureParameter.maColors, nColor, 0.0f); +} + +void RenderList::addDrawPolyLine(const basegfx::B2DPolygon& rPolygon, double fTransparency, + double fLineWidth, basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, double fMiterMinimumAngle, + Color nLineColor, bool bUseAA) +{ + if (rPolygon.count() <= 1) + return; + if (nLineColor == SALCOLOR_NONE) + return; + if (fTransparency == 1.0) + return; + + const bool bIsHairline = fLineWidth <= 1.2; + fLineWidth = bIsHairline ? 1.0f : fLineWidth; + + basegfx::B2DPolygon aPolygon(rPolygon); + if (rPolygon.areControlPointsUsed()) + aPolygon = rPolygon.getDefaultAdaptiveSubdivision(); + + checkOverlapping(aPolygon.getB2DRange()); + + RenderParameters& rParameter = maRenderEntries.back().maLineParameters; + + vcl::LineBuilder aBuilder(rParameter.maVertices, rParameter.maIndices, + nLineColor, fTransparency, fLineWidth, bUseAA); + + appendPolyLine(aBuilder, aPolygon, eLineJoin, eLineCap, fMiterMinimumAngle); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/framebuffer.cxx b/vcl/opengl/framebuffer.cxx new file mode 100644 index 000000000..db957d1a6 --- /dev/null +++ b/vcl/opengl/framebuffer.cxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include + +OpenGLFramebuffer::OpenGLFramebuffer() : + mnId( 0 ), + mnWidth( 0 ), + mnHeight( 0 ), + mnAttachedTexture( 0 ), + mpPrevFramebuffer( nullptr ) +{ + glGenFramebuffers( 1, &mnId ); + CHECK_GL_ERROR(); + VCL_GL_INFO( "Created framebuffer " << static_cast(mnId) ); +} + +OpenGLFramebuffer::~OpenGLFramebuffer() +{ + glDeleteFramebuffers( 1, &mnId ); + VCL_GL_INFO( "Deleted framebuffer " << static_cast(mnId) ); + CHECK_GL_ERROR(); +} + +void OpenGLFramebuffer::Bind(GLenum eTarget) +{ + VCL_GL_INFO( "Binding framebuffer " << static_cast(mnId) ); + glBindFramebuffer(eTarget, mnId); + CHECK_GL_ERROR(); +} + +void OpenGLFramebuffer::Unbind(GLenum eTarget) +{ + glBindFramebuffer(eTarget, 0); + CHECK_GL_ERROR(); + VCL_GL_INFO( "Binding default framebuffer" ); +} + +bool OpenGLFramebuffer::IsFree() const +{ + return !mnAttachedTexture; +} + +bool OpenGLFramebuffer::IsAttached( GLuint nTexture ) const +{ + return mnAttachedTexture == nTexture; +} + +bool OpenGLFramebuffer::IsAttached( const OpenGLTexture& rTexture ) const +{ + return mnAttachedTexture == rTexture.Id(); +} + +void OpenGLFramebuffer::AttachTexture( const OpenGLTexture& rTexture ) +{ + if( rTexture.Id() == mnAttachedTexture ) + return; + + VCL_GL_INFO( "Attaching texture " << rTexture.Id() << " to framebuffer " << static_cast(mnId) ); + mnAttachedTexture = rTexture.Id(); + mnWidth = rTexture.GetWidth(); + mnHeight = rTexture.GetHeight(); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mnAttachedTexture, 0); + CHECK_GL_ERROR(); + + GLuint nStencil = rTexture.StencilId(); + if( nStencil ) + { + VCL_GL_INFO( "Attaching stencil " << nStencil << " to framebuffer " << static_cast(mnId) ); + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, nStencil ); + CHECK_GL_ERROR(); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + CHECK_GL_ERROR(); + if (status != GL_FRAMEBUFFER_COMPLETE) + { + SAL_WARN("vcl.opengl", "Framebuffer incomplete"); + } +} + +void OpenGLFramebuffer::DetachTexture() +{ + if( mnAttachedTexture != 0 ) + { + mnAttachedTexture = 0; + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 ); + CHECK_GL_ERROR(); + + // FIXME: we could make this conditional on having a stencil ? + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, 0 ); + CHECK_GL_ERROR(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx new file mode 100644 index 000000000..6c76154ea --- /dev/null +++ b/vcl/opengl/gdiimpl.cxx @@ -0,0 +1,2315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +class OpenGLFlushIdle : public Idle +{ + OpenGLSalGraphicsImpl *m_pImpl; +public: + explicit OpenGLFlushIdle( OpenGLSalGraphicsImpl *pImpl ) + : Idle( "gl idle swap" ) + , m_pImpl( pImpl ) + { + // We don't want to be swapping before we've painted. + SetPriority( TaskPriority::POST_PAINT ); + } + + virtual void Invoke() override + { + m_pImpl->doFlush(); + Stop(); + SetPriority(TaskPriority::HIGHEST); + } +}; + +OpenGLSalGraphicsImpl::OpenGLSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider *pProvider) + : mrParent(rParent) + , mpProvider(pProvider) + , mpProgram(nullptr) + , mpFlush(new OpenGLFlushIdle(this)) + , mbUseScissor(false) + , mbUseStencil(false) + , mbXORMode(false) + , mbAcquiringOpenGLContext(false) + , mnLineColor(SALCOLOR_NONE) + , mnFillColor(SALCOLOR_NONE) +#ifdef DBG_UTIL + , mProgramIsSolidColor(false) +#endif + , mnDrawCount(0) + , mnDrawCountAtFlush(0) + , mProgramSolidColor(SALCOLOR_NONE) + , mProgramSolidTransparency(0.0) + , mpRenderList(new RenderList) +{ +} + +OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl() +{ + if( !IsOffscreen() && mnDrawCountAtFlush != mnDrawCount ) + VCL_GL_INFO( "Destroying un-flushed on-screen graphics" ); + + mpFlush.reset(); + + ReleaseContext(); +} + +rtl::Reference OpenGLSalGraphicsImpl::GetOpenGLContext() +{ + if (mbAcquiringOpenGLContext) + return nullptr; + mbAcquiringOpenGLContext = true; + bool bSuccess = AcquireContext(true); + mbAcquiringOpenGLContext = false; + if (!bSuccess) + return nullptr; + return mpContext; +} + +bool OpenGLSalGraphicsImpl::AcquireContext( bool bForceCreate ) +{ + mpContext = OpenGLContext::getVCLContext( false ); + + if( !mpContext.is() && mpWindowContext.is() ) + { + mpContext = mpWindowContext; + } + else if( bForceCreate && !IsOffscreen() ) + { + mpWindowContext = CreateWinContext(); + mpContext = mpWindowContext; + } + + if( !mpContext.is() ) + mpContext = OpenGLContext::getVCLContext(); + + return mpContext.is(); +} + +void OpenGLSalGraphicsImpl::ReleaseContext() +{ + mpContext.clear(); +} + +void OpenGLSalGraphicsImpl::Init() +{ + // Our init phase is strange ::Init is called twice for vdevs. + // the first time around with a NULL geometry provider. + if( !mpProvider ) + return; + + // check if we can simply re-use the same context + if( mpContext.is() ) + { + if( !UseContext( mpContext ) ) + ReleaseContext(); + } + + // Always create the offscreen texture + if( maOffscreenTex.GetWidth() != GetWidth() || + maOffscreenTex.GetHeight() != GetHeight() ) + { + // We don't want to be swapping before we've painted. + mpFlush->SetPriority( TaskPriority::POST_PAINT ); + + if( maOffscreenTex && // don't work to release empty textures + mpContext.is() ) // valid context + { + mpContext->makeCurrent(); + mpContext->ReleaseFramebuffer( maOffscreenTex ); + } + maOffscreenTex = OpenGLTexture(); + VCL_GL_INFO("::Init - re-size offscreen texture"); + } + + if( mpWindowContext.is() ) + { + mpWindowContext->reset(); + mpWindowContext.clear(); + } +} + +// Currently only used to get windows ordering right. +void OpenGLSalGraphicsImpl::DeInit() +{ + VCL_GL_INFO("::DeInit"); + + FlushDeferredDrawing(); + + // tdf#93839: + // Our window handles and resources are being free underneath us. + // These can be bound into a context, which relies on them. So + // let it know. Other eg. VirtualDevice contexts which have + // references on and rely on this context continuing to work will + // get a shiny new context in AcquireContext:: next PreDraw. + if( mpWindowContext.is() ) + { + mpWindowContext->reset(); + mpWindowContext.clear(); + } + mpContext.clear(); +} + +void OpenGLSalGraphicsImpl::PreDraw(XOROption eOpt) +{ + FlushDeferredDrawing(); + + InitializePreDrawState(eOpt); +} + +void OpenGLSalGraphicsImpl::InitializePreDrawState(XOROption eOpt) +{ + OpenGLZone::enter(); + + mnDrawCount++; + + if( !AcquireContext() ) + { + SAL_WARN( "vcl.opengl", "Couldn't acquire context" ); + return; + } + + mpContext->makeCurrent(); + CHECK_GL_ERROR(); + + CheckOffscreenTexture(); + CHECK_GL_ERROR(); + + mpContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight()))); + + ImplInitClipRegion(); + CHECK_GL_ERROR(); + + if (eOpt == IMPLEMENT_XOR && mbXORMode) + { + glEnable(GL_COLOR_LOGIC_OP); + CHECK_GL_ERROR(); + + glLogicOp(GL_XOR); + CHECK_GL_ERROR(); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + CHECK_GL_ERROR(); + } +} + +void OpenGLSalGraphicsImpl::PostDraw() +{ + if (mbXORMode) + { + glDisable(GL_COLOR_LOGIC_OP); + CHECK_GL_ERROR(); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + CHECK_GL_ERROR(); + } + + if( mpProgram ) + { + mpProgram->Clean(); + mpProgram = nullptr; +#ifdef DBG_UTIL + mProgramIsSolidColor = false; +#endif + } + + assert (maOffscreenTex); + + // Always queue the flush. + if( !IsOffscreen() ) + flush(); + + OpenGLZone::leave(); +} + +void OpenGLSalGraphicsImpl::PostBatchDraw() +{ + if (IsOffscreen()) + return; + + if (!mpFlush->IsActive()) + mpFlush->Start(); +} + +void OpenGLSalGraphicsImpl::ApplyProgramMatrices(float fPixelOffset) +{ + mpProgram->ApplyMatrix(GetWidth(), GetHeight(), fPixelOffset); +} + +void OpenGLSalGraphicsImpl::freeResources() +{ + // TODO Delete shaders, programs and textures if not shared + if( mpContext.is() && mpContext->isInitialized() ) + { + VCL_GL_INFO( "freeResources" ); + mpContext->makeCurrent(); + FlushDeferredDrawing(); + mpContext->ReleaseFramebuffer( maOffscreenTex ); + } + ReleaseContext(); +} + +void OpenGLSalGraphicsImpl::ImplSetClipBit( const vcl::Region& rClip, GLuint nMask ) +{ + mpContext->state().scissor().disable(); + mpContext->state().stencil().enable(); + + VCL_GL_INFO( "Adding complex clip / stencil" ); + GLuint nStencil = maOffscreenTex.StencilId(); + if( nStencil == 0 ) + { + nStencil = maOffscreenTex.AddStencil(); + glFramebufferRenderbuffer( + GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, nStencil ); + CHECK_GL_ERROR(); + } + // else - we associated the stencil in + // AcquireFrameBuffer / AttachTexture + + CHECK_GL_ERROR(); + glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); + CHECK_GL_ERROR(); + glStencilMask( nMask ); + CHECK_GL_ERROR(); + glStencilFunc( GL_NEVER, nMask, 0xFF ); + CHECK_GL_ERROR(); + glStencilOp( GL_REPLACE, GL_KEEP, GL_KEEP ); + CHECK_GL_ERROR(); + + glClear( GL_STENCIL_BUFFER_BIT ); + CHECK_GL_ERROR(); + if( UseSolid( Color( 0xFF, 0xFF, 0xFF ) ) ) + { + if( rClip.getRegionBand() ) + DrawRegionBand( *rClip.getRegionBand() ); + else + DrawPolyPolygon( rClip.GetAsB2DPolyPolygon(), true ); + } + + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + CHECK_GL_ERROR(); + glStencilMask( 0x00 ); + CHECK_GL_ERROR(); + + mpContext->state().stencil().disable(); +} + +void OpenGLSalGraphicsImpl::ImplInitClipRegion() +{ + // make sure the context has the right clipping set + if (maClipRegion != mpContext->maClipRegion) + { + mpContext->maClipRegion = maClipRegion; + if (mbUseStencil) + { + ImplSetClipBit(maClipRegion, 0x01); + } + } + + if (mbUseScissor) + { + tools::Rectangle aRect(maClipRegion.GetBoundRect()); + mpContext->state().scissor().set(aRect.Left(), GetHeight() - aRect.Bottom() - 1, aRect.GetWidth(), aRect.GetHeight()); + mpContext->state().scissor().enable(); + } + else + { + mpContext->state().scissor().disable(); + } + + if (mbUseStencil) + { + glStencilFunc( GL_EQUAL, 1, 0x1 ); + CHECK_GL_ERROR(); + mpContext->state().stencil().enable(); + } + else + { + mpContext->state().stencil().disable(); + } +} + +const vcl::Region& OpenGLSalGraphicsImpl::getClipRegion() const +{ + return maClipRegion; +} + +bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip ) +{ + if (maClipRegion == rClip) + { + VCL_GL_INFO("::setClipRegion (no change) " << rClip); + return true; + } + + FlushDeferredDrawing(); + + VCL_GL_INFO("::setClipRegion " << rClip); + + maClipRegion = rClip; + + mbUseStencil = false; + mbUseScissor = false; + if (maClipRegion.IsRectangle()) + mbUseScissor = true; + else if (!maClipRegion.IsEmpty()) + mbUseStencil = true; + + return true; +} + +// set the clip region to empty +void OpenGLSalGraphicsImpl::ResetClipRegion() +{ + if (maClipRegion.IsEmpty()) + { + VCL_GL_INFO("::ResetClipRegion (no change) "); + return; + } + + FlushDeferredDrawing(); + + VCL_GL_INFO("::ResetClipRegion"); + + maClipRegion.SetEmpty(); + mbUseScissor = false; + mbUseStencil = false; +} + +// get the depth of the device +sal_uInt16 OpenGLSalGraphicsImpl::GetBitCount() const +{ + return 32; +} + +// get the width of the device +long OpenGLSalGraphicsImpl::GetGraphicsWidth() const +{ + return GetWidth(); +} + +// set the line color to transparent (= don't draw lines) +void OpenGLSalGraphicsImpl::SetLineColor() +{ + if( mnLineColor != SALCOLOR_NONE ) + { + mnLineColor = SALCOLOR_NONE; + } +} + +// set the line color to a specific color +void OpenGLSalGraphicsImpl::SetLineColor( Color nColor ) +{ + if( mnLineColor != nColor ) + { + mnLineColor = nColor; + } +} + +// set the fill color to transparent (= don't fill) +void OpenGLSalGraphicsImpl::SetFillColor() +{ + if( mnFillColor != SALCOLOR_NONE ) + { + mnFillColor = SALCOLOR_NONE; + } +} + +// set the fill color to a specific color, shapes will be +// filled accordingly +void OpenGLSalGraphicsImpl::SetFillColor( Color nColor ) +{ + if( mnFillColor != nColor ) + { + mnFillColor = nColor; + } +} + +// enable/disable XOR drawing +void OpenGLSalGraphicsImpl::SetXORMode( bool bSet, bool ) +{ + if (mbXORMode != bSet) + { + FlushDeferredDrawing(); + mbXORMode = bSet; + } +} + +void OpenGLSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor) +{ + switch (nROPColor) + { + case SalROPColor::N0: + mnLineColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + mnLineColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + mnLineColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void OpenGLSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor) +{ + switch (nROPColor) + { + case SalROPColor::N0: + mnFillColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + mnFillColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + mnFillColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void OpenGLSalGraphicsImpl::CheckOffscreenTexture() +{ + bool bClearTexture = false; + + VCL_GL_INFO( "Check Offscreen texture" ); + + // Always create the offscreen texture + if( maOffscreenTex ) + { + if( maOffscreenTex.GetWidth() != GetWidth() || + maOffscreenTex.GetHeight() != GetHeight() ) + { + VCL_GL_INFO( "re-size offscreen texture " << maOffscreenTex.Id() ); + mpFlush->SetPriority( TaskPriority::POST_PAINT ); + mpContext->ReleaseFramebuffer( maOffscreenTex ); + maOffscreenTex = OpenGLTexture(); + } + } + + if( !maOffscreenTex ) + { + VCL_GL_INFO( "create texture of size " + << GetWidth() << " x " << GetHeight() ); + maOffscreenTex = OpenGLTexture( GetWidth(), GetHeight() ); + bClearTexture = true; + } + + if( !maOffscreenTex.IsUnique() ) + { + GLfloat fWidth = GetWidth(); + GLfloat fHeight = GetHeight(); + SalTwoRect aPosAry(0, 0, fWidth, fHeight, 0,0, fWidth, fHeight); + + // TODO: lfrb: User GL_ARB_copy_image? + OpenGLTexture aNewTex( GetWidth(), GetHeight() ); + + mpContext->state().scissor().disable(); + mpContext->state().stencil().disable(); + + mpContext->AcquireFramebuffer( aNewTex ); + DrawTexture( maOffscreenTex, aPosAry ); + maOffscreenTex = aNewTex; + } + else + { + mpContext->AcquireFramebuffer( maOffscreenTex ); + CHECK_GL_ERROR(); + + if( bClearTexture ) + { + glDrawBuffer( GL_COLOR_ATTACHMENT0 ); +#if OSL_DEBUG_LEVEL > 0 // lets have some red debugging background. + GLfloat const clearColor[4] = { 1.0, 0, 0, 0 }; +#else + GLfloat const clearColor[4] = { 1.0, 1.0, 1.0, 0 }; +#endif + glClearBufferfv( GL_COLOR, 0, clearColor ); + // FIXME: use glClearTexImage if we have it ? + } + } + + assert( maOffscreenTex ); + + CHECK_GL_ERROR(); +} + +bool OpenGLSalGraphicsImpl::UseProgram( const OUString& rVertexShader, const OUString& rFragmentShader, const OString& preamble ) +{ + if( mpProgram != nullptr ) + mpProgram->Clean(); + mpProgram = mpContext->UseProgram( rVertexShader, rFragmentShader, preamble ); +#ifdef DBG_UTIL + mProgramIsSolidColor = false; // UseSolid() will set to true if needed +#endif + return ( mpProgram != nullptr ); +} + +bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, sal_uInt8 nTransparency ) +{ + if( nColor == SALCOLOR_NONE ) + return false; + UseSolid(); + mpProgram->SetColor( "color", nColor, nTransparency ); +#ifdef DBG_UTIL + mProgramIsSolidColor = true; +#endif + mProgramSolidColor = nColor; + mProgramSolidTransparency = nTransparency / 100.0; + + return true; +} + +bool OpenGLSalGraphicsImpl::UseSolid( Color nColor, double fTransparency ) +{ + if( nColor == SALCOLOR_NONE ) + return false; + UseSolid(); + mpProgram->SetColorf( "color", nColor, fTransparency ); +#ifdef DBG_UTIL + mProgramIsSolidColor = true; +#endif + mProgramSolidColor = nColor; + mProgramSolidTransparency = fTransparency; + return true; +} + +void OpenGLSalGraphicsImpl::UseSolid() +{ + if (!UseProgram("combinedVertexShader", "combinedFragmentShader")) + return; + mpProgram->SetShaderType(DrawShaderType::Normal); +} + +bool OpenGLSalGraphicsImpl::UseInvert50() +{ + return UseProgram( "dumbVertexShader", "invert50FragmentShader" ); +} + +bool OpenGLSalGraphicsImpl::UseSolid( Color nColor ) +{ + return UseSolid( nColor, 0.0f ); +} + +bool OpenGLSalGraphicsImpl::UseInvert( SalInvert nFlags ) +{ + OpenGLZone aZone; + + if( ( nFlags & SalInvert::N50 ) || + ( nFlags & SalInvert::TrackFrame ) ) + { + // FIXME: Trackframe really should be 2 pix. on/off stipple. + if( !UseInvert50() ) + return false; + mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, + GL_ONE_MINUS_SRC_COLOR ); + } + else + { + if( !UseSolid( Color( 255, 255, 255 ) ) ) + return false; + mpProgram->SetBlendMode( GL_ONE_MINUS_DST_COLOR, GL_ZERO ); + } + return true; +} + +void OpenGLSalGraphicsImpl::DrawLineSegment(float x1, float y1, float x2, float y2) +{ + std::vector aVertices; + std::vector aExtrusionVectors; + + OpenGLZone aZone; + + glm::vec2 aPoint1(x1, y1); + glm::vec2 aPoint2(x2, y2); + + glm::vec2 aLineVector = vcl::vertex::normalize(aPoint2 - aPoint1); + glm::vec2 aNormal(-aLineVector.y, aLineVector.x); + + vcl::vertex::addLineSegmentVertices(aVertices, aExtrusionVectors, + aPoint1, aNormal, 1.0f, + aPoint2, aNormal, 1.0f); + + ApplyProgramMatrices(0.5f); + mpProgram->SetExtrusionVectors(aExtrusionVectors.data()); + mpProgram->DrawArrays(GL_TRIANGLES, aVertices); + + CHECK_GL_ERROR(); +} + +bool OpenGLSalGraphicsImpl::UseLine(Color nColor, double fTransparency, GLfloat fLineWidth, bool bUseAA) +{ + if( nColor == SALCOLOR_NONE ) + return false; + UseLine(fLineWidth, bUseAA); + mpProgram->SetColorf("color", nColor, fTransparency); +#ifdef DBG_UTIL + mProgramIsSolidColor = true; +#endif + mProgramSolidColor = nColor; + mProgramSolidTransparency = fTransparency; + return true; +} + +void OpenGLSalGraphicsImpl::UseLine(GLfloat fLineWidth, bool bUseAA) +{ + if (!UseProgram("combinedVertexShader", "combinedFragmentShader")) + return; + mpProgram->SetShaderType(DrawShaderType::Line); + mpProgram->SetUniform1f("line_width", fLineWidth); + // The width of the feather - area we make linearly transparent in VS. + // Good AA value is 0.5f, no AA if feather 0.0f + mpProgram->SetUniform1f("feather", bUseAA ? 0.5f : 0.0f); + // We need blending or AA won't work correctly + mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +} + +void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry, bool blockAA ) +{ + OpenGLZone aZone; + + std::vector aVertices(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++, j += 2 ) + { + aVertices[j] = GLfloat(pPtAry[i].mnX); + aVertices[j+1] = GLfloat(pPtAry[i].mnY); + } + + ApplyProgramMatrices(); + std::vector aExtrusion(nPoints * 3, 0); + mpProgram->SetExtrusionVectors(aExtrusion.data()); + mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices); + CHECK_GL_ERROR(); + + if( !blockAA && mrParent.getAntiAliasB2DDraw()) + { + // Make the edges antialiased by drawing the edge lines again with AA. + // TODO: If transparent drawing is set up, drawing the lines themselves twice + // may be a problem, if that is a real problem, the polygon areas itself needs to be + // masked out for this or something. +#ifdef DBG_UTIL + assert( mProgramIsSolidColor ); +#endif + Color lastSolidColor = mProgramSolidColor; + double lastSolidTransparency = mProgramSolidTransparency; + if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true)) + { + for( i = 0; i < nPoints; ++i ) + { + const SalPoint& rPt1 = pPtAry[ i ]; + const SalPoint& rPt2 = pPtAry[ ( i + 1 ) % nPoints ]; + DrawLineSegment(rPt1.mnX, rPt1.mnY, rPt2.mnX, rPt2.mnY); + } + UseSolid( lastSolidColor, lastSolidTransparency ); + } + } +} + +void OpenGLSalGraphicsImpl::DrawConvexPolygon( const tools::Polygon& rPolygon, bool blockAA ) +{ + OpenGLZone aZone; + + sal_uInt16 nPoints = rPolygon.GetSize() - 1; + std::vector aVertices(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++, j += 2 ) + { + const Point& rPt = rPolygon.GetPoint( i ); + aVertices[j] = GLfloat(rPt.X()); + aVertices[j+1] = GLfloat(rPt.Y()); + } + + ApplyProgramMatrices(); + std::vector aExtrusion(nPoints * 3, 0); + mpProgram->SetExtrusionVectors(aExtrusion.data()); + mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices); + CHECK_GL_ERROR(); + + if( !blockAA && mrParent.getAntiAliasB2DDraw()) + { + // Make the edges antialiased by drawing the edge lines again with AA. + // TODO: If transparent drawing is set up, drawing the lines themselves twice + // may be a problem, if that is a real problem, the polygon areas itself needs to be + // masked out for this or something. +#ifdef DBG_UTIL + assert( mProgramIsSolidColor ); +#endif + Color lastSolidColor = mProgramSolidColor; + double lastSolidTransparency = mProgramSolidTransparency; + if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true)) + { + for( i = 0; i < nPoints; ++i ) + { + const Point& rPt1 = rPolygon.GetPoint( i ); + const Point& rPt2 = rPolygon.GetPoint(( i + 1 ) % nPoints ); + DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY()); + } + UseSolid( lastSolidColor, lastSolidTransparency ); + } + } +} + +void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoid, bool blockAA ) +{ + OpenGLZone aZone; + + const basegfx::B2DPolygon& rPolygon = trapezoid.getB2DPolygon(); + sal_uInt16 nPoints = rPolygon.count(); + std::vector aVertices(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++, j += 2 ) + { + const basegfx::B2DPoint& rPt = rPolygon.getB2DPoint( i ); + aVertices[j] = GLfloat(rPt.getX()); + aVertices[j+1] = GLfloat(rPt.getY()); + } + + if (!mpProgram) + { + SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0"); + return; + } + + ApplyProgramMatrices(); + std::vector aExtrusion(nPoints * 3, 0); + mpProgram->SetExtrusionVectors(aExtrusion.data()); + mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices); + CHECK_GL_ERROR(); + + if( !blockAA && mrParent.getAntiAliasB2DDraw()) + { + // Make the edges antialiased by drawing the edge lines again with AA. + // TODO: If transparent drawing is set up, drawing the lines themselves twice + // may be a problem, if that is a real problem, the polygon areas itself needs to be + // masked out for this or something. +#ifdef DBG_UTIL + assert( mProgramIsSolidColor ); +#endif + Color lastSolidColor = mProgramSolidColor; + double lastSolidTransparency = mProgramSolidTransparency; + if (UseLine(lastSolidColor, lastSolidTransparency, 1.0f, true)) + { + for( i = 0; i < nPoints; ++i ) + { + const basegfx::B2DPoint& rPt1 = rPolygon.getB2DPoint( i ); + const basegfx::B2DPoint& rPt2 = rPolygon.getB2DPoint(( i + 1 ) % nPoints ); + DrawLineSegment(rPt1.getX(), rPt1.getY(), rPt2.getX(), rPt2.getY()); + } + UseSolid( lastSolidColor, lastSolidTransparency ); + } + } +} + +void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight ) +{ + long nX1( nX ); + long nY1( nY ); + long nX2( nX + nWidth ); + long nY2( nY + nHeight ); + const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 }, + { nX2, nY1 }, { nX2, nY2 }}; + + DrawConvexPolygon( 4, aPoints, true ); +} + +void OpenGLSalGraphicsImpl::DrawRect( const tools::Rectangle& rRect ) +{ + long nX1( rRect.Left() ); + long nY1( rRect.Top() ); + long nX2( rRect.Right() ); + long nY2( rRect.Bottom() ); + const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 }, + { nX2, nY1 }, { nX2, nY2 }}; + + DrawConvexPolygon( 4, aPoints, true ); +} + +void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + basegfx::B2DPolygon aPolygon; + + for( sal_uInt32 i = 0; i < nPoints; i++ ) + aPolygon.append( basegfx::B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) ); + aPolygon.setClosed( true ); + + if( basegfx::utils::isConvex( aPolygon ) ) + { + if( nPoints > 2 ) + DrawConvexPolygon( nPoints, pPtAry ); + } + else + { + const basegfx::B2DPolyPolygon aPolyPolygon( aPolygon ); + DrawPolyPolygon( aPolyPolygon ); + } +} + +void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, bool blockAA ) +{ + const basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::utils::solveCrossovers( rPolyPolygon ); + basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aSimplePolyPolygon ); + // draw tessellation result + for(const basegfx::B2DTrapezoid & i : aB2DTrapVector) + DrawTrapezoid( i, blockAA ); +} + +void OpenGLSalGraphicsImpl::DrawRegionBand( const RegionBand& rRegion ) +{ + OpenGLZone aZone; + + RectangleVector aRects; + std::vector aVertices; + rRegion.GetRegionRectangles( aRects ); + + if( aRects.empty() ) + return; + +#define ADD_VERTICE(pt) \ + aVertices.push_back(GLfloat(pt.X())); \ + aVertices.push_back(GLfloat(pt.Y())); + + for(tools::Rectangle & rRect : aRects) + { + rRect.AdjustBottom(1 ); + rRect.AdjustRight(1 ); + ADD_VERTICE( rRect.TopLeft() ); + ADD_VERTICE( rRect.TopRight() ); + ADD_VERTICE( rRect.BottomLeft() ); + ADD_VERTICE( rRect.BottomLeft() ); + ADD_VERTICE( rRect.TopRight() ); + ADD_VERTICE( rRect.BottomRight() ); + } +#undef ADD_VERTICE + std::vector aExtrusion(aRects.size() * 6 * 3, 0); + mpProgram->SetExtrusionVectors(aExtrusion.data()); + ApplyProgramMatrices(); + mpProgram->DrawArrays(GL_TRIANGLES, aVertices); + CHECK_GL_ERROR(); +} + +void OpenGLSalGraphicsImpl::DrawTextureRect( const SalTwoRect& rPosAry ) +{ + OpenGLZone aZone; + + SAL_INFO("vcl.opengl", "draw texture rect"); + + long nX = rPosAry.mnDestX; + long nY = rPosAry.mnDestY; + long nWidth = rPosAry.mnDestWidth; + long nHeight = rPosAry.mnDestHeight; + + std::vector aVertices; + aVertices.reserve(8); + vcl::vertex::addRectangle(aVertices, nX, nY, nX + nWidth, nY + nHeight); + + ApplyProgramMatrices(); + mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices); + CHECK_GL_ERROR(); +} + +void OpenGLSalGraphicsImpl::DrawTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted ) +{ + OpenGLZone aZone; + + SAL_INFO("vcl.opengl", "draw texture"); + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::Normal); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetTexture("texture", rTexture); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry, bInverted); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetMaskCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + DrawTextureRect( rPosAry ); + mpProgram->Clean(); +} + +namespace { + +bool scaleTexture(const rtl::Reference< OpenGLContext > &xContext, + OpenGLTexture& rOutTexture, const double& ixscale, const double& iyscale, OpenGLTexture& rTexture) +{ + int nWidth = rTexture.GetWidth(); + int nHeight = rTexture.GetHeight(); + if (nWidth == 0 || nHeight == 0) + return false; + + int nNewWidth = nWidth / ixscale; + int nNewHeight = nHeight / iyscale; + + OString sUseReducedRegisterVariantDefine; + if (xContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters) + sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n"); + + OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", "areaScaleFragmentShader", sUseReducedRegisterVariantDefine); + if (pProgram == nullptr) + return false; + + OpenGLTexture aScratchTex(nNewWidth, nNewHeight); + OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aScratchTex); + + // From OpenGLSalBitmap::ImplScaleArea(). + pProgram->SetUniform1f("xscale", ixscale); + pProgram->SetUniform1f("yscale", iyscale); + pProgram->SetUniform1i("swidth", nWidth); + pProgram->SetUniform1i("sheight", nHeight); + // For converting between <0,nWidth> and <0.0,1.0> coordinate systems. + GLfloat srcCoords[ 8 ]; + rTexture.GetWholeCoord( srcCoords ); + pProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] ); + pProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] ); + pProgram->SetUniform1f( "xtopixelratio", nNewWidth / ( srcCoords[ 4 ] - srcCoords[ 0 ] )); + pProgram->SetUniform1f( "ytopixelratio", nNewHeight / ( srcCoords[ 5 ] - srcCoords[ 1 ] )); + pProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth ); + pProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight ); + + pProgram->SetTexture("sampler", rTexture); + pProgram->DrawTexture(rTexture); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + + CHECK_GL_ERROR(); + + rOutTexture = aScratchTex; + return true; +} + +} + +void OpenGLSalGraphicsImpl::DrawTransformedTexture( + OpenGLTexture& rTexture, + OpenGLTexture& rMask, + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY ) +{ + OpenGLZone aZone; + + std::vector aVertices = { + 0, GLfloat(rTexture.GetHeight()), + 0, 0, + GLfloat(rTexture.GetWidth()), 0, + GLfloat(rTexture.GetWidth()), GLfloat(rTexture.GetHeight()) + }; + + GLfloat aTexCoord[8]; + + const long nDestWidth = basegfx::fround(basegfx::B2DVector(rX - rNull).getLength()); + const long nDestHeight = basegfx::fround(basegfx::B2DVector(rY - rNull).getLength()); + + // Invisibly small images shouldn't divide by zero. + if( nDestHeight == 0 || nDestWidth == 0 ) + return; + + // inverted scale ratios + double ixscale = rTexture.GetWidth() / double(nDestWidth); + double iyscale = rTexture.GetHeight() / double(nDestHeight); + + // If downscaling at a higher scale ratio, use the area scaling algorithm rather + // than plain OpenGL's scaling (texture mapping), for better results. + // See OpenGLSalBitmap::ImplScaleArea(). + bool areaScaling = false; + bool fastAreaScaling = false; + + OString sUseReducedRegisterVariantDefine; + if (mpContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters) + sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n"); + + OUString textureFragmentShader; + if( ixscale >= 2 && iyscale >= 2 ) // scale ratio less than 50% + { + areaScaling = true; + fastAreaScaling = ( ixscale == std::trunc( ixscale ) && iyscale == std::trunc( iyscale )); + // The generic case has arrays only up to 16 ratio downscaling and is performed in 2 passes, + // when the ratio is in the 16-100 range, which is hopefully enough in practice, but protect + // against buffer overflows in case such an extreme case happens (and in such case the precision + // of the generic algorithm probably doesn't matter anyway). + if( ixscale > 100 || iyscale > 100 ) + fastAreaScaling = true; + if( fastAreaScaling ) + textureFragmentShader = "areaScaleFastFragmentShader"; + else + textureFragmentShader = "areaScaleFragmentShader"; + } + + OpenGLTexture aInTexture = rTexture; + OpenGLTexture aInMask = rMask; + + // When using the area scaling algorithm we need to reduce the texture size in 2 passes + // in order to not use a big array inside the fragment shader. + if (areaScaling && !fastAreaScaling) + { + // Perform a first texture downscaling by an inverted scale ratio equal to + // the square root of the whole inverted scale ratio. + if (ixscale > 16 || iyscale > 16) + { + // The scissor area is set to the current window size in PreDraw, + // so if we do not disable the scissor test, the texture produced + // by the first downscaling is clipped to the current window size. + mpContext->state().scissor().disable(); + mpContext->state().stencil().disable(); + + // the square root of the whole inverted scale ratio + double ixscalesqrt = std::floor(std::sqrt(ixscale)); + double iyscalesqrt = std::floor(std::sqrt(iyscale)); + ixscale /= ixscalesqrt; // second pass inverted x-scale factor + iyscale /= iyscalesqrt; // second pass inverted y-scale factor + + scaleTexture(mpContext, aInTexture, ixscalesqrt, iyscalesqrt, rTexture); + + if (rMask) // we need to downscale the mask too + { + scaleTexture(mpContext, aInMask, ixscalesqrt, iyscalesqrt, rMask); + } + + // We need to re-acquire the off-screen texture. + CheckOffscreenTexture(); + CHECK_GL_ERROR(); + + // Re-enable scissor and stencil tests if needed. + if (mbUseScissor) + mpContext->state().scissor().enable(); + + if (mbUseStencil) + mpContext->state().stencil().enable(); + } + } + + if( aInMask ) + { + if( !UseProgram( "transformedTextureVertexShader", + textureFragmentShader.isEmpty() ? "maskedTextureFragmentShader" : textureFragmentShader, + "#define MASKED\n" + sUseReducedRegisterVariantDefine)) + return; + mpProgram->SetTexture( "mask", aInMask ); + GLfloat aMaskCoord[8]; + aInMask.GetWholeCoord(aMaskCoord); + mpProgram->SetMaskCoord(aMaskCoord); + aInMask.SetFilter( GL_LINEAR ); + mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + else + { + if( !UseProgram( "transformedTextureVertexShader", + textureFragmentShader.isEmpty() ? "textureFragmentShader" : textureFragmentShader, + sUseReducedRegisterVariantDefine)) + return; + } + + if(areaScaling) + { + int nWidth = aInTexture.GetWidth(); + int nHeight = aInTexture.GetHeight(); + + // From OpenGLSalBitmap::ImplScaleArea(). + if (fastAreaScaling && nWidth && nHeight) + { + mpProgram->SetUniform1i( "xscale", ixscale ); + mpProgram->SetUniform1i( "yscale", iyscale ); + GLfloat srcCoords[ 8 ]; + aInTexture.GetWholeCoord( srcCoords ); + mpProgram->SetUniform1f( "xstep", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth ); + mpProgram->SetUniform1f( "ystep", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight ); + mpProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale )); + } + else if (nHeight > 1 && nWidth > 1) + { + mpProgram->SetUniform1f( "xscale", ixscale ); + mpProgram->SetUniform1f( "yscale", iyscale ); + mpProgram->SetUniform1i( "swidth", nWidth ); + mpProgram->SetUniform1i( "sheight", nHeight ); + // For converting between <0,nWidth-1> and <0.0,1.0> coordinate systems. + GLfloat srcCoords[ 8 ]; + aInTexture.GetWholeCoord( srcCoords ); + mpProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] ); + mpProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] ); + mpProgram->SetUniform1f( "xtopixelratio", ( nWidth / ixscale ) / ( srcCoords[ 4 ] - srcCoords[ 0 ] )); + mpProgram->SetUniform1f( "ytopixelratio", ( nHeight / iyscale ) / ( srcCoords[ 5 ] - srcCoords[ 1 ] )); + mpProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / nWidth ); + mpProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / nHeight ); + } + } + + ApplyProgramMatrices(); + mpProgram->SetUniform2f( "viewport", GetWidth(), GetHeight() ); + // Here, in order to get the correct transformation we need to pass the original texture, + // since it has been used for initializing the rectangle vertices. + mpProgram->SetTransform( "transform", rTexture, rNull, rX, rY ); + aInTexture.GetWholeCoord(aTexCoord); + mpProgram->SetTexture("sampler", aInTexture); + aInTexture.SetFilter(GL_LINEAR); + mpProgram->SetTextureCoord( aTexCoord ); + mpProgram->DrawArrays(GL_TRIANGLE_FAN, aVertices); + + CHECK_GL_ERROR(); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::DrawAlphaTexture( OpenGLTexture& rTexture, const SalTwoRect& rPosAry, bool bInverted, bool bPremultiplied ) +{ + OpenGLZone aZone; + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::Normal); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetTexture("texture", rTexture); + mpProgram->SetBlendMode( bPremultiplied ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA ); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry, bInverted); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetMaskCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + DrawTextureRect( rPosAry ); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::DrawTextureDiff( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry, bool bInverted ) +{ + OpenGLZone aZone; + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::Diff); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetTexture( "texture", rTexture ); + mpProgram->SetTexture( "mask", rMask ); + mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry, bInverted); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + GLfloat aMaskCoord[8]; + rMask.GetCoord(aMaskCoord, rPosAry, bInverted); + mpProgram->SetMaskCoord(aMaskCoord); + + DrawTextureRect( rPosAry ); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::DrawTextureWithMask( OpenGLTexture& rTexture, OpenGLTexture& rMask, const SalTwoRect& rPosAry ) +{ + OpenGLZone aZone; + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::Masked); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetTexture( "texture", rTexture ); + mpProgram->SetTexture( "mask", rMask ); + mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + GLfloat aMaskCoord[8]; + rMask.GetCoord(aMaskCoord, rPosAry); + mpProgram->SetMaskCoord(aMaskCoord); + + DrawTextureRect(rPosAry); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::DrawBlendedTexture( OpenGLTexture& rTexture, OpenGLTexture& rMask, OpenGLTexture& rAlpha, const SalTwoRect& rPosAry ) +{ + OpenGLZone aZone; + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::Blend); + mpProgram->SetTexture( "texture", rTexture ); + mpProgram->SetTexture( "mask", rMask ); + mpProgram->SetTexture( "alpha", rAlpha ); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry); + mpProgram->SetTextureCoord(aTexCoord); + + GLfloat aAlphaCoord[8]; + rAlpha.GetCoord(aAlphaCoord, rPosAry); + mpProgram->SetAlphaCoord(aAlphaCoord); + + GLfloat aMaskCoord[8]; + rMask.GetCoord(aMaskCoord, rPosAry); + mpProgram->SetMaskCoord(aMaskCoord); + + mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + DrawTextureRect( rPosAry ); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::DrawMask( OpenGLTexture& rMask, Color nMaskColor, const SalTwoRect& rPosAry ) +{ + OpenGLZone aZone; + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return; + mpProgram->SetShaderType(TextureShaderType::MaskedColor); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetColor( "color", nMaskColor, 0 ); + mpProgram->SetTexture("texture", rMask); + + GLfloat aTexCoord[8]; + rMask.GetCoord(aTexCoord, rPosAry); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetMaskCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + mpProgram->SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + DrawTextureRect(rPosAry); + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::FlushLinesOrTriangles(DrawShaderType eType, RenderParameters const & rParameters) +{ + if (!UseProgram("combinedVertexShader", "combinedFragmentShader", "#define USE_VERTEX_COLORS")) + return; + + mpProgram->SetShaderType(eType); + mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + ApplyProgramMatrices(0.5f); + + vcl::VertexBufferObject vbo; + vbo.upload(rParameters.maVertices); + + GLuint positionAttrib = SAL_MAX_UINT32; + GLuint colorAttrib = SAL_MAX_UINT32; + GLuint lineDataAttrib = SAL_MAX_UINT32; + + mpProgram->SetVertexAttrib(positionAttrib, "position", 2, GL_FLOAT, GL_FALSE, + sizeof(Vertex), reinterpret_cast(offsetof(Vertex, position))); + + mpProgram->SetVertexAttrib(colorAttrib, "vertex_color_in", 4, GL_FLOAT, GL_FALSE, + sizeof(Vertex), reinterpret_cast(offsetof(Vertex, color))); + + mpProgram->SetVertexAttrib(lineDataAttrib, "extrusion_vectors", 4, GL_FLOAT, GL_FALSE, + sizeof(Vertex), reinterpret_cast(offsetof(Vertex, lineData))); + + vcl::IndexBufferObject ibo; + ibo.upload(rParameters.maIndices); + ibo.bind(); + + mpProgram->DrawElements(GL_TRIANGLES, rParameters.maIndices.size()); + CHECK_GL_ERROR(); + + mpProgram->Clean(); +} + +void OpenGLSalGraphicsImpl::FlushDeferredDrawing() +{ + if (mpRenderList->empty()) + return; + + VCL_GL_INFO("FlushDeferredDrawing: " << mpRenderList->getEntries().size()); + + InitializePreDrawState(XOROption::IMPLEMENT_XOR); + + OpenGLZone aZone; + for (RenderEntry& rRenderEntry : mpRenderList->getEntries()) + { + if (rRenderEntry.hasTriangles()) + { + RenderParameters& rParameters = rRenderEntry.maTriangleParameters; + VCL_GL_INFO("Flush Triangles: " << rParameters.maVertices.size()); + FlushLinesOrTriangles(DrawShaderType::Normal, rParameters); + } + if (rRenderEntry.hasLines()) + { + RenderParameters& rParameters = rRenderEntry.maLineParameters; + VCL_GL_INFO("Flush Lines: " << rParameters.maVertices.size()); + FlushLinesOrTriangles(DrawShaderType::Line, rParameters); + } + if (rRenderEntry.hasTextures() && UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader", "#define USE_VERTEX_COLORS")) + { + mpProgram->SetShaderType(TextureShaderType::MaskedColor); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetBlendMode(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + for (auto& rPair : rRenderEntry.maTextureParametersMap) + { + RenderTextureParameters& rParameters = rPair.second; + mpProgram->SetTexture("texture", rParameters.maTexture); + ApplyProgramMatrices(); + mpProgram->SetTextureCoord(rParameters.maTextureCoords.data()); + mpProgram->SetMaskCoord(rParameters.maTextureCoords.data()); + mpProgram->SetAlphaCoord(rParameters.maTextureCoords.data()); + mpProgram->SetVertexColors(rParameters.maColors); + mpProgram->DrawArrays(GL_TRIANGLES, rParameters.maVertices); + CHECK_GL_ERROR(); + } + mpProgram->Clean(); + } + } + + mpRenderList->clear(); + PostDraw(); + + VCL_GL_INFO("End FlushDeferredDrawing"); +} + +void OpenGLSalGraphicsImpl::DrawLinearGradient( const Gradient& rGradient, const tools::Rectangle& rRect ) +{ + OpenGLZone aZone; + + if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) ) + return; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nFactor = rGradient.GetStartIntensity(); + mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor ); + nFactor = rGradient.GetEndIntensity(); + mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor ); + + tools::Rectangle aBoundRect; + Point aCenter; + rGradient.GetBoundRect( rRect, aBoundRect, aCenter ); + tools::Polygon aPoly( aBoundRect ); + aPoly.Rotate( aCenter, rGradient.GetAngle() % 3600 ); + + GLfloat aTexCoord[8] = { 0, 1, 1, 1, 1, 0, 0, 0 }; + GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder()); + aTexCoord[5] = aTexCoord[7] = fMin; + mpProgram->SetTextureCoord( aTexCoord ); + DrawConvexPolygon( aPoly, true ); +} + +void OpenGLSalGraphicsImpl::DrawAxialGradient( const Gradient& rGradient, const tools::Rectangle& rRect ) +{ + OpenGLZone aZone; + + if( !UseProgram( "textureVertexShader", "linearGradientFragmentShader" ) ) + return; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nFactor = rGradient.GetStartIntensity(); + mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor ); + nFactor = rGradient.GetEndIntensity(); + mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor ); + + /** + * Draw two rectangles with linear gradient. + * + * 1 *---* 2 + * | /| + * | / | Points 0 and 3 have start color + * 0 |/__| 3 Points 1, 2, 4 and 5 have end color + * |\ | + * | \ | + * | \| + * 5 *---* 4 + * + */ + + tools::Rectangle aRect; + Point aCenter; + rGradient.GetBoundRect( rRect, aRect, aCenter ); + + // determine points 0 and 3 + Point aPt0( aRect.Left(), (aRect.Top() + aRect.Bottom() + 1) / 2 ); + Point aPt3( aRect.Right(), (aRect.Top() + aRect.Bottom() + 1) / 2 ); + + tools::Polygon aPoly( 7 ); + aPoly.SetPoint( aPt0, 0 ); + aPoly.SetPoint( aRect.TopLeft(), 1 ); + aPoly.SetPoint( aRect.TopRight(), 2 ); + aPoly.SetPoint( aPt3, 3 ); + aPoly.SetPoint( aRect.BottomRight(), 4 ); + aPoly.SetPoint( aRect.BottomLeft(), 5 ); + aPoly.SetPoint( aPt0, 6 ); + aPoly.Rotate( aCenter, rGradient.GetAngle() % 3600 ); + + GLfloat aTexCoord[12] = { 0, 1, 1, 0, 2, 0, 3, 1, 4, 0, 5, 0 }; + GLfloat fMin = 1.0 - 100.0 / (100.0 - rGradient.GetBorder()); + aTexCoord[3] = aTexCoord[5] = aTexCoord[9] = aTexCoord[11] = fMin; + mpProgram->SetTextureCoord( aTexCoord ); + DrawConvexPolygon( aPoly, true ); +} + +void OpenGLSalGraphicsImpl::DrawRadialGradient( const Gradient& rGradient, const tools::Rectangle& rRect ) +{ + OpenGLZone aZone; + + if( !UseProgram( "textureVertexShader", "radialGradientFragmentShader" ) ) + return; + Color aStartCol = rGradient.GetStartColor(); + Color aEndCol = rGradient.GetEndColor(); + long nFactor = rGradient.GetStartIntensity(); + mpProgram->SetColorWithIntensity( "start_color", aStartCol, nFactor ); + nFactor = rGradient.GetEndIntensity(); + mpProgram->SetColorWithIntensity( "end_color", aEndCol, nFactor ); + + tools::Rectangle aRect; + Point aCenter; + rGradient.GetBoundRect( rRect, aRect, aCenter ); + + // adjust coordinates so that radius has distance equals to 1.0 + double fRadius = aRect.GetWidth() / 2.0f; + GLfloat fWidth = rRect.GetWidth() / fRadius; + GLfloat fHeight = rRect.GetHeight() / fRadius; + GLfloat aTexCoord[8] = { 0, 0, 0, fHeight, fWidth, fHeight, fWidth, 0 }; + mpProgram->SetTextureCoord( aTexCoord ); + mpProgram->SetUniform2f( "center", (aCenter.X() - rRect.Left()) / fRadius, + (aCenter.Y() - rRect.Top()) / fRadius ); + DrawRect( rRect ); +} + +void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY) +{ + VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")"); + mpRenderList->addDrawPixel(nX, nY, mnLineColor); + PostBatchDraw(); +} + +void OpenGLSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor) +{ + VCL_GL_INFO("::drawPixel: (" << nX << ", " << nY << ")"); + mpRenderList->addDrawPixel(nX, nY, nColor); + PostBatchDraw(); +} + +void OpenGLSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2) +{ + VCL_GL_INFO("::drawLine (" << nX1 << ", " << nY1 << ") (" << nX2 << ", " << nY2 << ")"); + mpRenderList->addDrawLine(nX1, nY1, nX2, nY2, mnLineColor, mrParent.getAntiAliasB2DDraw()); + PostBatchDraw(); +} + +void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + VCL_GL_INFO("::drawRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]"); + mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, 0.0, mnLineColor, mnFillColor); + PostBatchDraw(); +} + +void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + VCL_GL_INFO("::drawPolyLine legacy -> redirecting to drawPolyLine"); + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + aPoly.setClosed(false); + + drawPolyLine( + basegfx::B2DHomMatrix(), + aPoly, + 0.0, + 1.0, + nullptr, // MM01 + basegfx::B2DLineJoin::Miter, + css::drawing::LineCap_BUTT, + basegfx::deg2rad(15.0) /*default*/, + false); +} + +void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + VCL_GL_INFO("::drawPolygon legacy -> redirecting to drawPolyPolygon with transparency"); + basegfx::B2DPolygon aPoly; + aPoly.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + basegfx::B2DPolyPolygon(aPoly), + 0.0); +} + +void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPointCounts, PCONSTSALPOINT* pPtAry ) +{ + VCL_GL_INFO("::drawPolyPolygon legacy -> redirecting to drawPolyPolygon with transparency"); + basegfx::B2DPolyPolygon aPolyPoly; + for(sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon) + { + sal_uInt32 nPoints = pPointCounts[nPolygon]; + if (nPoints) + { + PCONSTSALPOINT pPoints = pPtAry[nPolygon]; + basegfx::B2DPolygon aPoly; + aPoly.append( basegfx::B2DPoint(pPoints->mnX, pPoints->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPoly.setB2DPoint(i, basegfx::B2DPoint( pPoints[i].mnX, pPoints[i].mnY)); + + aPolyPoly.append(aPoly); + } + } + + drawPolyPolygon( + basegfx::B2DHomMatrix(), + aPolyPoly, + 0.0); +} + +bool OpenGLSalGraphicsImpl::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ + VCL_GL_INFO("::drawPolyPolygon " << rPolyPolygon.getB2DRange()); + + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + // FlushLinesOrTriangles() works with a 0.5 pixel offset, compensate for that here. + basegfx::B2DHomMatrix aMatrix; + aMatrix.translate(-0.5f, -0.5f); + aPolyPolygon.transform(aMatrix); + + mpRenderList->addDrawPolyPolygon( + aPolyPolygon, + fTransparency, + mnLineColor, + mnFillColor, + mrParent.getAntiAliasB2DDraw()); + + PostBatchDraw(); + return true; +} + +bool OpenGLSalGraphicsImpl::drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolygon, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) +{ + VCL_GL_INFO("::drawPolyLine " << rPolygon.getB2DRange()); + + // MM01 check done for simple reasons + if(!rPolygon.count() || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + assert(!bStrokeUsed || (bStrokeUsed && pStroke)); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolygon, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolygon); + } + + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline + aPolyPolygonLine.transform(rObjectToDevice); + if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); } + + // tdf#124848 get correct LineWidth in discrete coordinates, + if(fLineWidth == 0) // hairline + fLineWidth = 1.0; + else // Adjust line width for object-to-device scale. + fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); + + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + // addDrawPolyLine() assumes that there are no duplicate points in the polygon + basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + basegfx::utils::simplifyCurveSegments(aPolyLine); + aPolyLine.removeDoublePoints(); + + mpRenderList->addDrawPolyLine( + aPolyLine, + fTransparency, + fLineWidth, + eLineJoin, + eLineCap, + fMiterMinimumAngle, + mnLineColor, + mrParent.getAntiAliasB2DDraw()); + + // MM01: not sure - maybe this can be moved out of this loop, but to + // keep on the safe side for now, do not really change something for now + PostBatchDraw(); + } + + return true; +} + +bool OpenGLSalGraphicsImpl::drawPolyLineBezier( + sal_uInt32 /*nPoints*/, + const SalPoint* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/ ) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::drawPolygonBezier( + sal_uInt32 /*nPoints*/, + const SalPoint* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/ ) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier( + sal_uInt32 /*nPoly*/, + const sal_uInt32* /*pPoints*/, + const SalPoint* const* /*pPtAry*/, + const PolyFlags* const* /*pFlgAry*/ ) +{ + return false; +} + +// CopyArea --> No RasterOp, but ClipRegion +void OpenGLSalGraphicsImpl::copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, bool /*bWindowInvalidate*/ ) +{ + VCL_GL_INFO( "::copyArea " << nSrcX << "," << nSrcY << " >> " << nDestX << "," << nDestY << " (" << nSrcWidth << "," << nSrcHeight << ")" ); + OpenGLTexture aTexture; + SalTwoRect aPosAry(0, 0, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight); + + PreDraw(); + // TODO offscreen case + aTexture = OpenGLTexture( nSrcX, GetHeight() - nSrcY - nSrcHeight, + nSrcWidth, nSrcHeight ); + DrawTexture( aTexture, aPosAry ); + PostDraw(); +} + +// CopyBits and DrawBitmap --> RasterOp and ClipRegion +// CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics +void OpenGLSalGraphicsImpl::DoCopyBits( const SalTwoRect& rPosAry, OpenGLSalGraphicsImpl& rImpl ) +{ + VCL_GL_INFO( "::copyBits" ); + + rImpl.FlushDeferredDrawing(); + + if( !rImpl.maOffscreenTex ) + { + VCL_GL_INFO( "::copyBits - skipping copy of un-initialized framebuffer contents of size " + << rImpl.GetWidth() << "x" << rImpl.GetHeight() ); + return; + } + + if( &rImpl == this && + (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight)) + { + // short circuit if there is nothing to do + if( (rPosAry.mnSrcX == rPosAry.mnDestX) && + (rPosAry.mnSrcY == rPosAry.mnDestY)) + return; + // use copyArea() if source and destination context are identical + copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, false/*bWindowInvalidate*/ ); + return; + } + + PreDraw(); + DrawTexture( rImpl.maOffscreenTex, rPosAry ); + PostDraw(); +} + +void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) +{ + // check that carefully only in the debug mode + assert(dynamic_cast(&rSalBitmap)); + + OpenGLZone aZone; + + const OpenGLSalBitmap& rBitmap = static_cast(rSalBitmap); + OpenGLTexture& rTexture = rBitmap.GetTexture(); + + VCL_GL_INFO( "::drawBitmap" ); + PreDraw(); + if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || + rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + { + basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY); + basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY); + basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight); + OpenGLTexture mask; // no mask set + DrawTransformedTexture(rTexture, mask, aNull, aX, aY); + } + else + { + DrawTexture( rTexture, rPosAry ); + } + PostDraw(); +} + +void OpenGLSalGraphicsImpl::drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) +{ + VCL_GL_INFO("::drawBitmap with MASK -> redirect to ::drawAlphaBitmap"); + drawAlphaBitmap(rPosAry, rSalBitmap, rMaskBitmap); +} + +void OpenGLSalGraphicsImpl::drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + Color nMaskColor ) +{ + VCL_GL_INFO("::drawMask"); + + assert(dynamic_cast(&rSalBitmap)); + const OpenGLSalBitmap& rBitmap = static_cast(rSalBitmap); + mpRenderList->addDrawTextureWithMaskColor(rBitmap.GetTexture(), nMaskColor, rPosAry); + PostBatchDraw(); +} + +std::shared_ptr OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long nHeight ) +{ + FlushDeferredDrawing(); + + OpenGLZone aZone; + + std::shared_ptr pBitmap(std::make_shared()); + VCL_GL_INFO( "::getBitmap " << nX << "," << nY << + " " << nWidth << "x" << nHeight ); + //TODO really needed? + PreDraw(); + pBitmap->Create( maOffscreenTex, nX, nY, nWidth, nHeight ); + PostDraw(); + return pBitmap; +} + +Color OpenGLSalGraphicsImpl::getPixel( long nX, long nY ) +{ + FlushDeferredDrawing(); + + char pixel[3] = { 0, 0, 0 }; + + PreDraw( XOROption::IMPLEMENT_XOR ); + nY = GetHeight() - nY - 1; + glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel); + CHECK_GL_ERROR(); + PostDraw(); + + return Color( pixel[0], pixel[1], pixel[2] ); +} + +// invert --> ClipRegion (only Windows or VirDevs) +void OpenGLSalGraphicsImpl::invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) +{ + PreDraw(); + + if( UseInvert( nFlags ) ) + { + if( nFlags & SalInvert::TrackFrame ) + { // FIXME: could be more efficient. + DrawRect( nX, nY, nWidth, 1 ); + DrawRect( nX, nY + nHeight, nWidth, 1 ); + DrawRect( nX, nY, 1, nHeight ); + DrawRect( nX + nWidth, nY, 1, nHeight ); + } + else + DrawRect( nX, nY, nWidth, nHeight ); + } + + PostDraw(); +} + +void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) +{ + PreDraw(); + + if( UseInvert( nFlags ) ) + { + if (nFlags & SalInvert::TrackFrame) + { + // Track frame means the invert50FragmentShader must remain active + // (to draw what looks like a dashed line), so DrawLineSegment() + // can't be used. Draw the edge of the polygon as polygons instead. + for (size_t nPoint = 0; nPoint < nPoints; ++nPoint) + { + const SalPoint& rFrom = pPtAry[nPoint]; + const SalPoint& rTo = pPtAry[(nPoint + 1) % nPoints]; + if (rFrom.mnX == rTo.mnX) + { + // Extend to the right, comments assuming "to" is above + // "from": + const SalPoint aPoints[] = { { rFrom.mnX + 1, rFrom.mnY }, // bottom right + { rFrom.mnX, rFrom.mnY }, // bottom left + { rTo.mnX, rTo.mnY }, // top left + { rTo.mnX + 1, rTo.mnY } }; // top right + DrawConvexPolygon(4, aPoints, true); + } + else + { + // Otherwise can extend downwards, comments assuming "to" + // is above and on the right of "from": + const SalPoint aPoints[] = { { rFrom.mnX, rFrom.mnY + 1 }, // bottom left + { rFrom.mnX, rFrom.mnY }, // top left + { rTo.mnX, rTo.mnY }, // top right + { rTo.mnX, rTo.mnY + 1 } }; // bottom right + DrawConvexPolygon(4, aPoints, true); + } + } + } + else + DrawPolygon(nPoints, pPtAry); + } + + PostDraw(); +} + +bool OpenGLSalGraphicsImpl::drawEPS( + long /*nX*/, long /*nY*/, + long /*nWidth*/, long /*nHeight*/, + void* /*pPtr*/, + sal_uInt32 /*nSize*/ ) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::blendBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap ) +{ + assert(dynamic_cast(&rSalBitmap)); + + OpenGLZone aZone; + + const OpenGLSalBitmap& rBitmap = static_cast(rSalBitmap); + OpenGLTexture& rTexture( rBitmap.GetTexture() ); + + VCL_GL_INFO( "::blendBitmap" ); + PreDraw(); + + if (!UseProgram("combinedTextureVertexShader", "combinedTextureFragmentShader")) + return true; + + mpProgram->SetShaderType(TextureShaderType::Normal); + mpProgram->SetIdentityTransform("transform"); + mpProgram->SetTexture("texture", rTexture); + + GLfloat aTexCoord[8]; + rTexture.GetCoord(aTexCoord, rPosAry); + mpProgram->SetTextureCoord(aTexCoord); + mpProgram->SetMaskCoord(aTexCoord); + mpProgram->SetAlphaCoord(aTexCoord); + + mpProgram->SetBlendMode(GL_ZERO, GL_SRC_COLOR); + DrawTextureRect(rPosAry); + mpProgram->Clean(); + + PostDraw(); + return true; +} + +bool OpenGLSalGraphicsImpl::blendAlphaBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalSrcBitmap, + const SalBitmap& rSalMaskBitmap, + const SalBitmap& rSalAlphaBitmap ) +{ + assert(dynamic_cast(&rSalSrcBitmap)); + assert(dynamic_cast(&rSalMaskBitmap)); + assert(dynamic_cast(&rSalAlphaBitmap)); + + OpenGLZone aZone; + + const OpenGLSalBitmap& rSrcBitmap = static_cast(rSalSrcBitmap); + const OpenGLSalBitmap& rMaskBitmap = static_cast(rSalMaskBitmap); + const OpenGLSalBitmap& rAlphaBitmap = static_cast(rSalAlphaBitmap); + OpenGLTexture& rTexture( rSrcBitmap.GetTexture() ); + OpenGLTexture& rMask( rMaskBitmap.GetTexture() ); + OpenGLTexture& rAlpha( rAlphaBitmap.GetTexture() ); + + VCL_GL_INFO( "::blendAlphaBitmap" ); + PreDraw(); + DrawBlendedTexture( rTexture, rMask, rAlpha, rPosAry ); + PostDraw(); + return true; +} + +/** 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 + */ +bool OpenGLSalGraphicsImpl::drawAlphaBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rAlphaBitmap ) +{ + assert(dynamic_cast(&rSalBitmap)); + assert(dynamic_cast(&rAlphaBitmap)); + + OpenGLZone aZone; + + const OpenGLSalBitmap& rBitmap = static_cast(rSalBitmap); + const OpenGLSalBitmap& rAlpha = static_cast(rAlphaBitmap); + OpenGLTexture& rTexture(rBitmap.GetTexture()); + OpenGLTexture& rAlphaTexture(rAlpha.GetTexture()); + + VCL_GL_INFO( "::drawAlphaBitmap" ); + PreDraw(); + + if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || + rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + { + basegfx::B2DPoint aNull(rPosAry.mnDestX,rPosAry.mnDestY); + basegfx::B2DPoint aX(rPosAry.mnDestX + rPosAry.mnDestWidth, rPosAry.mnDestY); + basegfx::B2DPoint aY(rPosAry.mnDestX, rPosAry.mnDestY + rPosAry.mnDestHeight); + DrawTransformedTexture(rTexture, rAlphaTexture, aNull, aX, aY); + } + else + { + DrawTextureWithMask( rTexture, rAlphaTexture, rPosAry ); + } + + PostDraw(); + return true; +} + +/** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ +bool OpenGLSalGraphicsImpl::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSrcBitmap, + const SalBitmap* pAlphaBitmap) +{ + assert(dynamic_cast(&rSrcBitmap)); + assert(!pAlphaBitmap || dynamic_cast(pAlphaBitmap)); + + OpenGLZone aZone; + + const OpenGLSalBitmap& rBitmap = static_cast(rSrcBitmap); + const OpenGLSalBitmap* pMaskBitmap = static_cast(pAlphaBitmap); + OpenGLTexture& rTexture( rBitmap.GetTexture() ); + OpenGLTexture aMask; // no texture + + if( pMaskBitmap != nullptr ) + aMask = pMaskBitmap->GetTexture(); + + VCL_GL_INFO( "::drawTransformedBitmap" ); + PreDraw(); + DrawTransformedTexture( rTexture, aMask, rNull, rX, rY ); + PostDraw(); + + return true; +} + +/** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ +bool OpenGLSalGraphicsImpl::drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) +{ + VCL_GL_INFO("::drawAlphaRect (" << nX << ", " << nY << ") [" << nWidth << ", " << nHeight << "]"); + mpRenderList->addDrawRectangle(nX, nY, nWidth, nHeight, nTransparency / 100.0, mnLineColor, mnFillColor); + PostBatchDraw(); + return true; +} + +bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolyPoly, + const Gradient& rGradient) +{ + tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + + VCL_GL_INFO("::drawGradient " << rPolyPoly.GetBoundRect()); + + if (aBoundRect.IsEmpty()) + { + VCL_GL_INFO("::drawGradient nothing to draw"); + return true; + } + + if (rGradient.GetStyle() != GradientStyle::Linear && + rGradient.GetStyle() != GradientStyle::Axial && + rGradient.GetStyle() != GradientStyle::Radial ) + { + VCL_GL_INFO("::drawGradient unsupported gradient type"); + return false; + } + + aBoundRect.AdjustLeft( -1 ); + aBoundRect.AdjustTop( -1 ); + aBoundRect.AdjustRight( 1 ); + aBoundRect.AdjustBottom( 1 ); + + PreDraw( XOROption::IMPLEMENT_XOR ); + +#define FIXME_BROKEN_STENCIL_FOR_GRADIENTS 0 +#if FIXME_BROKEN_STENCIL_FOR_GRADIENTS + ImplSetClipBit( vcl::Region( rPolyPoly ), 0x02 ); + if( mbUseStencil ) + { + mpContext->state().stencil().enable(); + CHECK_GL_ERROR(); + glStencilFunc( GL_EQUAL, 3, 0xFF ); + CHECK_GL_ERROR(); + } + else + { + mpContext->state().stencil().enable(); + CHECK_GL_ERROR(); + glStencilFunc( GL_EQUAL, 2, 0xFF ); + CHECK_GL_ERROR(); + } +#endif + + // if border >= 100%, draw solid rectangle with start color + if (rGradient.GetBorder() >= 100.0) + { + VCL_GL_INFO("::drawGradient -> DrawRect (no gradient)"); + + Color aColor = rGradient.GetStartColor(); + long nIntensity = rGradient.GetStartIntensity(); + if (UseSolid(Color(aColor.GetRed() * nIntensity / 100.0, + aColor.GetGreen()* nIntensity / 100.0, + aColor.GetBlue() * nIntensity / 100.0))) + { + DrawRect(aBoundRect); + } + } + else if (rGradient.GetStyle() == GradientStyle::Linear) + { + VCL_GL_INFO("::drawGradient -> DrawLinearGradient"); + DrawLinearGradient(rGradient, aBoundRect); + } + else if (rGradient.GetStyle() == GradientStyle::Axial) + { + VCL_GL_INFO("::drawGradient -> DrawAxialGradient"); + DrawAxialGradient(rGradient, aBoundRect); + } + else if (rGradient.GetStyle() == GradientStyle::Radial) + { + VCL_GL_INFO("::drawGradient -> DrawRadialGradient"); + DrawRadialGradient(rGradient, aBoundRect); + } + +#if FIXME_BROKEN_STENCIL_FOR_GRADIENTS + if( !mbUseStencil ) + { + mpContext->state().stencil().disable(); + CHECK_GL_ERROR(); + } +#endif + PostDraw(); + + return true; +} + +void OpenGLSalGraphicsImpl::flush() +{ + FlushDeferredDrawing(); + + if( IsOffscreen() ) + return; + + if( !Application::IsInExecute() ) + { + // otherwise nothing would trigger idle rendering + doFlush(); + } + else if( !mpFlush->IsActive() ) + mpFlush->Start(); +} + +void OpenGLSalGraphicsImpl::doFlush() +{ + FlushDeferredDrawing(); + + if (OpenGLContext::hasCurrent()) + { + mpContext->state().scissor().disable(); + mpContext->state().stencil().disable(); + } + + if( IsOffscreen() ) + return; + + if( !maOffscreenTex ) + { + VCL_GL_INFO( "doFlush - odd no texture !" ); + return; + } + + if( mnDrawCountAtFlush == mnDrawCount ) + { + VCL_GL_INFO( "eliding redundant doFlush, no drawing since last!" ); + return; + } + + mnDrawCountAtFlush = mnDrawCount; + + OpenGLZone aZone; + + VCL_GL_INFO( "doFlush" ); + + if( !mpWindowContext.is() ) + { + // ensure everything is released from the old context. + OpenGLContext::clearCurrent(); + mpWindowContext = CreateWinContext(); + VCL_GL_INFO( "late creation of window context" ); + } + + assert( mpWindowContext.is() ); + + if( !mpWindowContext.is() ) + { + // failed to create a GL context for this window: + // eg. mis-matching pixel formats, underlying window + // resource lifecycle, etc. + VCL_GL_INFO( "Failed to create window context" ); + return; + } + + // Interesting ! -> this destroys a context [ somehow ] ... + mpWindowContext->makeCurrent(); + CHECK_GL_ERROR(); + + VCL_GL_INFO( "doFlush - acquire default framebuffer" ); + + mpWindowContext->AcquireDefaultFramebuffer(); + + CHECK_GL_ERROR(); + + mpWindowContext->state().sync(); + mpWindowContext->state().viewport(tools::Rectangle(Point(0, 0), Size(GetWidth(), GetHeight()))); + mpWindowContext->state().scissor().disable(); + mpWindowContext->state().stencil().disable(); + +#if OSL_DEBUG_LEVEL > 0 // random background glClear + glClearColor(static_cast(double(rand())/RAND_MAX), + static_cast(double(rand())/RAND_MAX), + static_cast(double(rand())/RAND_MAX), 1.0); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + CHECK_GL_ERROR(); +#endif + + VCL_GL_INFO( "Texture height " << maOffscreenTex.GetHeight() << " vs. window height " << GetHeight() ); + + OpenGLFramebuffer* pFrameBuffer = mpWindowContext->AcquireFramebuffer(maOffscreenTex); + CHECK_GL_ERROR(); + if (pFrameBuffer) + { + OpenGLFramebuffer::Unbind(GL_DRAW_FRAMEBUFFER); + pFrameBuffer->Bind(GL_READ_FRAMEBUFFER); + + glBlitFramebuffer(0, 0, GetWidth(), GetHeight(), + 0, 0, GetWidth(), GetHeight(), GL_COLOR_BUFFER_BIT, GL_NEAREST); + CHECK_GL_ERROR(); + + pFrameBuffer->Bind(); + } + + static bool bNoSwap = getenv("SAL_GL_NO_SWAP"); + if (!bNoSwap) + mpWindowContext->swapBuffers(); + + VCL_GL_INFO( "doFlush - end." ); +} + +bool OpenGLSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const +{ + switch (eType) + { + case OutDevSupportType::B2DDraw: + case OutDevSupportType::TransparentRect: + return true; + default: + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/opengl_blacklist_windows.xml b/vcl/opengl/opengl_blacklist_windows.xml new file mode 100644 index 000000000..71e562fa9 --- /dev/null +++ b/vcl/opengl/opengl_blacklist_windows.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vcl/opengl/program.cxx b/vcl/opengl/program.cxx new file mode 100644 index 000000000..6557eccf8 --- /dev/null +++ b/vcl/opengl/program.cxx @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include + +#include +#include +#include + +OpenGLProgram::OpenGLProgram() : + mnId( 0 ), + mnEnabledAttribs( 0 ), + mnPositionAttrib( SAL_MAX_UINT32 ), + mnTexCoordAttrib( SAL_MAX_UINT32 ), + mnAlphaCoordAttrib( SAL_MAX_UINT32 ), + mnMaskCoordAttrib( SAL_MAX_UINT32 ), + mnExtrusionVectorsAttrib( SAL_MAX_UINT32 ), + mnVertexColorsAttrib( SAL_MAX_UINT32 ), + mbBlending(false), + mfLastWidth(0.0), + mfLastHeight(0.0), + mfLastPixelOffset(0.0) +{ +} + +OpenGLProgram::~OpenGLProgram() +{ + maUniformLocations.clear(); + if( mnId != 0 ) + { + glDeleteProgram( mnId ); + CHECK_GL_ERROR(); + } +} + +bool OpenGLProgram::Load( const OUString& rVertexShader, + const OUString& rFragmentShader, + const OString& preamble, + const OString& rDigest ) +{ + mnId = OpenGLHelper::LoadShaders( rVertexShader, rFragmentShader, preamble, rDigest ); + return ( mnId != 0 ); +} + +void OpenGLProgram::Reuse() +{ + mbBlending = false; +} + +void OpenGLProgram::Use() +{ + if (!mnId) + return; + + glUseProgram(mnId); + CHECK_GL_ERROR(); + Reuse(); +} + +void OpenGLProgram::Clean() +{ + // unbind all textures + for (OpenGLTexture& rTexture : maTextures) + { + rTexture.Unbind(); + } + maTextures.clear(); + + // disable any enabled vertex attrib array + if( mnEnabledAttribs ) + { + for( int i = 0; i < 32; i++ ) + { + if( mnEnabledAttribs & ( 1 << i ) ) + { + glDisableVertexAttribArray( i ); + CHECK_GL_ERROR(); + } + } + mnEnabledAttribs = 0; + } +} + +bool OpenGLProgram::EnableVertexAttrib(GLuint& rAttrib, const OString& rName) +{ + if( rAttrib == SAL_MAX_UINT32 ) + { + GLint aLocation = glGetAttribLocation(mnId, rName.getStr()); + CHECK_GL_ERROR(); + if (aLocation < 0) + return false; + rAttrib = GLuint(aLocation); + } + if( (mnEnabledAttribs & ( 1 << rAttrib )) == 0 ) + { + glEnableVertexAttribArray( rAttrib ); + CHECK_GL_ERROR(); + mnEnabledAttribs |= ( 1 << rAttrib ); + } + return true; +} + +void OpenGLProgram::SetVertexAttrib(GLuint& rAttrib, const OString& rName, GLint nSize, + GLenum eType, GLboolean bNormalized, GLsizei aStride, + const GLvoid* pPointer) +{ + if (EnableVertexAttrib(rAttrib, rName)) + { + glVertexAttribPointer(rAttrib, nSize, eType, bNormalized, aStride, pPointer); + CHECK_GL_ERROR(); + } + else + { + VCL_GL_INFO("Vertex attribute '" << rName << "' doesn't exist in this program (" << mnId << ")"); + } +} + +void OpenGLProgram::SetVertices( const GLvoid* pData ) +{ + SetVertexAttrib(mnPositionAttrib, "position", 2, GL_FLOAT, GL_FALSE, 0, pData); +} + +void OpenGLProgram::SetTextureCoord( const GLvoid* pData ) +{ + SetVertexAttrib(mnTexCoordAttrib, "tex_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData); +} + +void OpenGLProgram::SetAlphaCoord( const GLvoid* pData ) +{ + SetVertexAttrib(mnAlphaCoordAttrib, "alpha_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData); +} + +void OpenGLProgram::SetMaskCoord(const GLvoid* pData) +{ + SetVertexAttrib(mnMaskCoordAttrib, "mask_coord_in", 2, GL_FLOAT, GL_FALSE, 0, pData); +} + +void OpenGLProgram::SetExtrusionVectors(const GLvoid* pData) +{ + SetVertexAttrib(mnExtrusionVectorsAttrib, "extrusion_vectors", 3, GL_FLOAT, GL_FALSE, 0, pData); +} + +void OpenGLProgram::SetVertexColors(std::vector& rColorVector) +{ + SetVertexAttrib(mnVertexColorsAttrib, "vertex_color_in", 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, rColorVector.data()); +} + +void OpenGLProgram::SetShaderType(TextureShaderType eTextureShaderType) +{ + SetUniform1i("type", GLint(eTextureShaderType)); +} + +void OpenGLProgram::SetShaderType(DrawShaderType eDrawShaderType) +{ + SetUniform1i("type", GLint(eDrawShaderType)); +} + +GLuint OpenGLProgram::GetUniformLocation( const OString& rName ) +{ + auto it = maUniformLocations.find( rName ); + if( it == maUniformLocations.end() ) + { + GLuint nLocation = glGetUniformLocation( mnId, rName.getStr() ); + CHECK_GL_ERROR(); + maUniformLocations[rName] = nLocation; + return nLocation; + } + + return it->second; +} + +void OpenGLProgram::DrawArrays(GLenum aMode, std::vector& aVertices) +{ + if (!mbBlending) + OpenGLContext::getVCLContext()->state().blend().disable(); + + SetVertices(aVertices.data()); + glDrawArrays(aMode, 0, aVertices.size() / 2); +} + +void OpenGLProgram::DrawElements(GLenum aMode, GLuint nNumberOfVertices) +{ + if (!mbBlending) + OpenGLContext::getVCLContext()->state().blend().disable(); + + glDrawElements(aMode, nNumberOfVertices, GL_UNSIGNED_INT, nullptr); +} + +void OpenGLProgram::SetUniform1f( const OString& rName, GLfloat v1 ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform1f( nUniform, v1 ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetUniform2f( const OString& rName, GLfloat v1, GLfloat v2 ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform2f( nUniform, v1, v2 ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetUniform1fv( const OString& rName, GLsizei nCount, GLfloat const * aValues ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform1fv( nUniform, nCount, aValues ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetUniform2fv( const OString& rName, GLsizei nCount, GLfloat const * aValues ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform2fv( nUniform, nCount, aValues ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetUniform1i( const OString& rName, GLint v1 ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform1i( nUniform, v1 ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetColor( const OString& rName, Color nColor, sal_uInt8 nTransparency ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform4f( nUniform, + nColor.GetRed() / 255.0f, + nColor.GetGreen() / 255.0f, + nColor.GetBlue() / 255.0f, + (100 - nTransparency) * (1.0 / 100) ); + CHECK_GL_ERROR(); + + if( nTransparency > 0 ) + SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); +} + +void OpenGLProgram::SetColorf( const OString& rName, Color nColor, double fTransparency ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform4f( nUniform, + nColor.GetRed() / 255.0f, + nColor.GetGreen() / 255.0f, + nColor.GetBlue() / 255.0f, + (1.0f - fTransparency) ); + CHECK_GL_ERROR(); + + if( fTransparency > 0.0 ) + SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); +} + +void OpenGLProgram::SetColor( const OString& rName, const Color& rColor ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform4f( nUniform, + static_cast(rColor.GetRed()) / 255, + static_cast(rColor.GetGreen()) / 255, + static_cast(rColor.GetBlue()) / 255, + 1.0f - static_cast(rColor.GetTransparency()) / 255 ); + CHECK_GL_ERROR(); + + if( rColor.GetTransparency() > 0 ) + SetBlendMode( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); +} + +void OpenGLProgram::SetColorWithIntensity( const OString& rName, const Color& rColor, long nFactor ) +{ + GLuint nUniform = GetUniformLocation( rName ); + glUniform4f( nUniform, + static_cast(rColor.GetRed()) * nFactor / 25500.0, + static_cast(rColor.GetGreen()) * nFactor / 25500.0, + static_cast(rColor.GetBlue()) * nFactor / 25500.0, + 1.0f ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetTexture( const OString& rName, OpenGLTexture& rTexture ) +{ + GLuint nUniform = GetUniformLocation( rName ); + int nIndex = maTextures.size(); + + glUniform1i( nUniform, nIndex ); + CHECK_GL_ERROR(); + + OpenGLContext::getVCLContext()->state().texture().active(nIndex); + + rTexture.Bind(); + maTextures.push_back(rTexture); +} + +void OpenGLProgram::SetTransform( + const OString& rName, + const OpenGLTexture& rTexture, + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY ) +{ + auto nTexWidth = rTexture.GetWidth(); + auto nTexHeight = rTexture.GetHeight(); + if (nTexWidth == 0 || nTexHeight == 0) + return; + + GLuint nUniform = GetUniformLocation( rName ); + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + const float aValues[] = { + static_cast(aXRel.getX())/nTexWidth, static_cast(aXRel.getY())/nTexWidth, 0, 0, + static_cast(aYRel.getX())/nTexHeight, static_cast(aYRel.getY())/nTexHeight, 0, 0, + 0, 0, 1, 0, + static_cast(rNull.getX()), static_cast(rNull.getY()), 0, 1 }; + glm::mat4 aMatrix = glm::make_mat4( aValues ); + glUniformMatrix4fv( nUniform, 1, GL_FALSE, glm::value_ptr( aMatrix ) ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetIdentityTransform(const OString& rName) +{ + GLuint nUniform = GetUniformLocation(rName); + glm::mat4 aMatrix {}; + glUniformMatrix4fv(nUniform, 1, GL_FALSE, glm::value_ptr( aMatrix ) ); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::ApplyMatrix(float fWidth, float fHeight, float fPixelOffset) +{ + + if (mfLastWidth == fWidth && mfLastHeight == fHeight && mfLastPixelOffset == fPixelOffset) + return; + + mfLastWidth = fWidth; + mfLastHeight = fHeight; + mfLastPixelOffset = fPixelOffset; + + GLuint nUniform = GetUniformLocation("mvp"); + + glm::mat4 aMVP = glm::ortho(0.0f, fWidth, fHeight, 0.0f, 0.0f, 1.0f); + + if (fPixelOffset != 0.0f) + aMVP = glm::translate(aMVP, glm::vec3(fPixelOffset, fPixelOffset, 0.0f)); + + glUniformMatrix4fv(nUniform, 1, GL_FALSE, glm::value_ptr(aMVP)); + CHECK_GL_ERROR(); +} + +void OpenGLProgram::SetBlendMode(GLenum nSFactor, GLenum nDFactor) +{ + OpenGLContext::getVCLContext()->state().blend().enable(); + OpenGLContext::getVCLContext()->state().blend().func(nSFactor, nDFactor); + mbBlending = true; +} + +void OpenGLProgram::DrawTexture( const OpenGLTexture& rTexture ) +{ + if (!rTexture) + return; + + float fWidth = rTexture.GetWidth(); + float fHeight = rTexture.GetHeight(); + + float fMinX = 0.0f; + float fMaxX = fWidth; + float fMinY = 0.0f; + float fMaxY = fHeight; + + std::vector aPosition { + fMinX, fMaxY, + fMinX, fMinY, + fMaxX, fMinY, + fMaxX, fMaxY + }; + GLfloat aTexCoord[8]; + + rTexture.GetWholeCoord( aTexCoord ); + SetTextureCoord( aTexCoord ); + ApplyMatrix(fWidth, fHeight); + DrawArrays(GL_TRIANGLE_FAN, aPosition); + CHECK_GL_ERROR(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx new file mode 100644 index 000000000..e9b1bca73 --- /dev/null +++ b/vcl/opengl/salbmp.cxx @@ -0,0 +1,783 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if OSL_DEBUG_LEVEL > 0 +# define CANARY "tex-canary" +#endif + +namespace +{ + +bool determineTextureFormat(sal_uInt16 nBits, GLenum& nFormat, GLenum& nType) +{ + switch(nBits) + { + case 8: + nFormat = GL_LUMINANCE; + nType = GL_UNSIGNED_BYTE; + return true; + case 24: + nFormat = GL_RGB; + nType = GL_UNSIGNED_BYTE; + return true; + case 32: + nFormat = GL_RGBA; + nType = GL_UNSIGNED_BYTE; + return true; + default: + break; + } + SAL_WARN("vcl.opengl", "Could not determine the appropriate texture format for input bits '" << nBits << "'"); + return false; +} + +bool isValidBitCount( sal_uInt16 nBitCount ) +{ + return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 24) || (nBitCount == 32); +} + +sal_uInt32 lclBytesPerRow(sal_uInt16 nBits, int nWidth) +{ + switch(nBits) + { + case 1: return (nWidth + 7) >> 3; + case 4: return (nWidth + 1) >> 1; + case 8: return nWidth; + case 24: return nWidth * 3; + case 32: return nWidth * 4; + default: + OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!"); + } + return 0; +} +} + +OpenGLSalBitmap::OpenGLSalBitmap() +: mbDirtyTexture(true) +, mnBits(0) +, mnBytesPerRow(0) +, mnWidth(0) +, mnHeight(0) +{ +} + +OpenGLSalBitmap::~OpenGLSalBitmap() +{ + Destroy(); + VCL_GL_INFO( "~OpenGLSalBitmap" ); +} + +void OpenGLSalBitmap::Create( const OpenGLTexture& rTex, long nX, long nY, long nWidth, long nHeight ) +{ + DBG_TESTSOLARMUTEX(); + static const BitmapPalette aEmptyPalette; + OpenGLVCLContextZone aContextZone; + + Destroy(); + VCL_GL_INFO( "OpenGLSalBitmap::Create from FBO: [" + << nX << ", " << nY << "] " << nWidth << "x" << nHeight ); + + GLint nMaxTextureSize; + glGetIntegerv( GL_MAX_TEXTURE_SIZE, &nMaxTextureSize ); + if ( nWidth > nMaxTextureSize ) + { + nWidth = nMaxTextureSize; + VCL_GL_INFO( "Width limited to " << nMaxTextureSize ); + } + + if ( nHeight > nMaxTextureSize ) + { + nHeight = nMaxTextureSize; + VCL_GL_INFO( "Height limited to " << nMaxTextureSize ); + } + + mnWidth = nWidth; + mnHeight = nHeight; + + // TODO Check the framebuffer configuration + mnBits = 32; + maPalette = aEmptyPalette; + + if( rTex ) + maTexture = OpenGLTexture( rTex, nX, nY, nWidth, nHeight ); + else + maTexture = OpenGLTexture( nX, nY, nWidth, nHeight ); + mbDirtyTexture = false; + VCL_GL_INFO( "Created texture " << maTexture.Id() ); + + assert(mnWidth == maTexture.GetWidth() && + mnHeight == maTexture.GetHeight()); +} + +bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette ) +{ + DBG_TESTSOLARMUTEX(); + OpenGLVCLContextZone aContextZone; + + Destroy(); + VCL_GL_INFO( "OpenGLSalBitmap::Create with size: " << rSize ); + + if( !isValidBitCount( nBits ) ) + return false; + maPalette = rBitmapPalette; + mnBits = nBits; + mnWidth = rSize.Width(); + mnHeight = rSize.Height(); + + // Limit size to what GL allows, so later glTexImage2D() won't fail. + GLint nMaxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize); + if (mnWidth > nMaxTextureSize) + mnWidth = nMaxTextureSize; + if (mnHeight > nMaxTextureSize) + mnHeight = nMaxTextureSize; + + return false; +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp ) +{ + DBG_TESTSOLARMUTEX(); + return Create( rSalBmp, rSalBmp.GetBitCount() ); +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) +{ + DBG_TESTSOLARMUTEX(); + return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() ); +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) +{ + DBG_TESTSOLARMUTEX(); + OpenGLZone aZone; + + // check that carefully only in the debug mode + assert(dynamic_cast(&rSalBmp)); + + const OpenGLSalBitmap& rSourceBitmap = static_cast(rSalBmp); + + VCL_GL_INFO("OpenGLSalBitmap::Create from BMP: " + << rSourceBitmap.mnWidth << "x" << rSourceBitmap.mnHeight + << " Bits old: " << mnBits << " new:" << nNewBitCount ); + + if( isValidBitCount( nNewBitCount ) ) + { + // TODO: lfrb: What about the pending operations?! + mnBits = nNewBitCount; + mnBytesPerRow = rSourceBitmap.mnBytesPerRow; + mnWidth = rSourceBitmap.mnWidth; + mnHeight = rSourceBitmap.mnHeight; + maPalette = rSourceBitmap.maPalette; + // execute any pending operations on the source bitmap + maTexture = rSourceBitmap.GetTexture(); + mbDirtyTexture = false; + + // be careful here, we are share & reference-count the + // mpUserBuffer, BUT this Create() is called from + // Bitmap::ImplMakeUnique(). + // Consequently, there might be cases when this needs to be made + // unique later (when we don't do that right away here), like when + // using the BitmapWriteAccess. + mpUserBuffer = rSourceBitmap.mpUserBuffer; + + return true; + } + return false; +} + +bool OpenGLSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ ) +{ + DBG_TESTSOLARMUTEX(); + // TODO Is this method needed? + return false; +} + +OpenGLTexture& OpenGLSalBitmap::GetTexture() const +{ + OpenGLSalBitmap* pThis = const_cast(this); + if( !maTexture || mbDirtyTexture ) + pThis->CreateTexture(); + VCL_GL_INFO( "Got texture " << maTexture.Id() ); + return pThis->maTexture; +} + +void OpenGLSalBitmap::Destroy() +{ + OpenGLZone aZone; + + VCL_GL_INFO("Destroy OpenGLSalBitmap texture:" << maTexture.Id()); + maTexture = OpenGLTexture(); + DeallocateUserData(); +} + +bool OpenGLSalBitmap::AllocateUserData() +{ + VCL_GL_INFO( "OpenGLSalBitmap::AllocateUserData" ); + + if( mnWidth && mnHeight ) + { + mnBytesPerRow = lclBytesPerRow(mnBits, mnWidth); + } + + bool alloc = false; + if (mnBytesPerRow != 0 && mnHeight && + mnBytesPerRow <= std::numeric_limits::max() / mnHeight) + { + try + { + size_t nToAllocate = mnBytesPerRow * mnHeight; +#if OSL_DEBUG_LEVEL > 0 + nToAllocate += sizeof(CANARY); +#endif + mpUserBuffer = o3tl::make_shared_array(nToAllocate); +#if OSL_DEBUG_LEVEL > 0 + memcpy(mpUserBuffer.get() + nToAllocate - sizeof(CANARY), + CANARY, sizeof(CANARY)); +#endif + alloc = true; + } + catch (const std::bad_alloc &) {} + } + if (!alloc) + { + SAL_WARN("vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight); + DeallocateUserData(); + } +#ifdef DBG_UTIL + else + { + for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++) + mpUserBuffer.get()[i] = (i & 0xFF); + } +#endif + + return mpUserBuffer != nullptr; +} + +void OpenGLSalBitmap::DeallocateUserData() +{ + mpUserBuffer.reset(); + mnBytesPerRow = 0; +} + +namespace { + +void lclInstantiateTexture(OpenGLTexture& rTexture, const int nWidth, const int nHeight, + const GLenum nFormat, const GLenum nType, sal_uInt8 const * pData) +{ + if (nWidth == nHeight) + { + typedef std::vector> TextureAtlasVector; + static vcl::DeleteOnDeinit aTextureAtlases([]() { + TextureAtlasVector* p = new TextureAtlasVector; + p->reserve(5); + p->push_back(std::make_unique(8, 8, 16)); + p->push_back(std::make_unique(8, 8, 24)); + p->push_back(std::make_unique(8, 8, 32)); + p->push_back(std::make_unique(8, 8, 48)); + p->push_back(std::make_unique(8, 8, 64)); + return p; + }()); + for (std::unique_ptr& pTextureAtlas : *aTextureAtlases.get()) + { + if (nWidth == pTextureAtlas->GetSubtextureSize()) + { + rTexture = pTextureAtlas->InsertBuffer(nWidth, nHeight, nFormat, nType, pData); + return; + } + } + } + rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData); +} + +} // end anonymous namespace + +Size OpenGLSalBitmap::GetSize() const +{ + return Size(mnWidth, mnHeight); +} + +GLuint OpenGLSalBitmap::CreateTexture() +{ + VCL_GL_INFO( "::CreateTexture bits: " << mnBits); + GLenum nFormat = GL_RGBA; + GLenum nType = GL_UNSIGNED_BYTE; + sal_uInt8* pData( nullptr ); + bool bAllocated( false ); + + if (mpUserBuffer != nullptr) + { + if( mnBits == 24 || mnBits == 32 ) + { + // no conversion needed for truecolor + pData = mpUserBuffer.get(); + + determineTextureFormat(mnBits, nFormat, nType); + } + else if( mnBits == 8 && maPalette.IsGreyPalette8Bit() ) + { + // no conversion needed for 8bit grayscale + pData = mpUserBuffer.get(); + nFormat = GL_LUMINANCE; + nType = GL_UNSIGNED_BYTE; + } + else + { + VCL_GL_INFO( "::CreateTexture - convert from " << mnBits << " to 24 bits" ); + // convert to 24 bits RGB using palette + determineTextureFormat(24, nFormat, nType); + pData = convertDataBitCount( mpUserBuffer.get(), mnWidth, mnHeight, + mnBits, mnBytesPerRow, maPalette, + nFormat == GL_BGR ? BitConvert::BGR : BitConvert::RGB ).release(); + bAllocated = true; + } + } + + OpenGLVCLContextZone aContextZone; + + lclInstantiateTexture(maTexture, mnWidth, mnHeight, nFormat, nType, pData); + + VCL_GL_INFO("Created texture " << maTexture.Id() << " bits: " << mnBits); + + if( bAllocated ) + delete[] pData; + + mbDirtyTexture = false; + + CHECK_GL_ERROR(); + return maTexture.Id(); +} + +bool OpenGLSalBitmap::ReadTexture() +{ + sal_uInt8* pData = mpUserBuffer.get(); + + GLenum nFormat = GL_RGBA; + GLenum nType = GL_UNSIGNED_BYTE; + + VCL_GL_INFO( "::ReadTexture " << mnWidth << "x" << mnHeight << " bits: " << mnBits); + + if( pData == nullptr ) + return false; + + OpenGLVCLContextZone aContextZone; + + rtl::Reference xContext = OpenGLContext::getVCLContext(); + xContext->state().scissor().disable(); + xContext->state().stencil().disable(); + + if ((mnBits == 8 && maPalette.IsGreyPalette8Bit()) || mnBits == 24 || mnBits == 32) + { + determineTextureFormat(mnBits, nFormat, nType); + +#if OSL_DEBUG_LEVEL > 0 + // help valgrind & drmemory rescue us - touch last and first bits. + pData[0] = 0; + pData[mnBits/8*mnWidth*mnHeight-1] = 0; + // if this fails we can read too much into pData + assert(mnWidth == maTexture.GetWidth() && + mnHeight == maTexture.GetHeight()); +#endif + + maTexture.Read(nFormat, nType, pData); + +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + // If we read over the end of pData we have a real hidden memory + // corruption problem ! + size_t nCanary = mnBytesPerRow * mnHeight; + assert(!memcmp(pData + nCanary, CANARY, sizeof (CANARY))); +#endif + return true; + } + else if (mnBits == 1 || mnBits == 4 || mnBits == 8) + { // convert buffers from 24-bit RGB to 1,4 or 8-bit buffer + std::vector aBuffer(mnWidth * mnHeight * 3); + + sal_uInt8* pBuffer = aBuffer.data(); + determineTextureFormat(24, nFormat, nType); + maTexture.Read(nFormat, nType, pBuffer); + sal_uInt32 nSourceBytesPerRow = lclBytesPerRow(24, mnWidth); + + std::unique_ptr pWriter = vcl::ScanlineWriter::Create(mnBits, maPalette); + for (int y = 0; y < mnHeight; ++y) + { + sal_uInt8* pSource = &pBuffer[y * nSourceBytesPerRow]; + sal_uInt8* pDestination = &pData[y * mnBytesPerRow]; + + pWriter->nextLine(pDestination); + + for (int x = 0; x < mnWidth; ++x) + { + // read source + sal_uInt8 nR = *pSource++; + sal_uInt8 nG = *pSource++; + sal_uInt8 nB = *pSource++; + + pWriter->writeRGB(nR, nG, nB); + } + } + return true; + } + + SAL_WARN("vcl.opengl", "::ReadTexture - tx:" << maTexture.Id() << " @ " + << mnWidth << "x" << mnHeight << "- unimplemented bit depth: " + << mnBits); + return false; +} + +sal_uInt16 OpenGLSalBitmap::GetBitCount() const +{ + return mnBits; +} + +bool OpenGLSalBitmap::calcChecksumGL(OpenGLTexture& rInputTexture, BitmapChecksum& rChecksum) const +{ + OUString FragShader("areaHashCRC64TFragmentShader"); + + rtl::Reference< OpenGLContext > xContext = OpenGLContext::getVCLContext(); + xContext->state().scissor().disable(); + xContext->state().stencil().disable(); + + static vcl::DeleteOnDeinit gCRCTableTexture( + new OpenGLTexture(512, 1, GL_RGBA, GL_UNSIGNED_BYTE, + vcl_get_crc64_table())); + OpenGLTexture &rCRCTableTexture = *gCRCTableTexture.get(); + + // First Pass + + int nWidth = rInputTexture.GetWidth(); + int nHeight = rInputTexture.GetHeight(); + + OpenGLProgram* pProgram = xContext->UseProgram("textureVertexShader", FragShader); + if (pProgram == nullptr) + return false; + + int nNewWidth = ceil( nWidth / 4.0 ); + int nNewHeight = ceil( nHeight / 4.0 ); + + OpenGLTexture aFirstPassTexture(nNewWidth, nNewHeight); + OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer(aFirstPassTexture); + + pProgram->SetUniform1f( "xstep", 1.0 / mnWidth ); + pProgram->SetUniform1f( "ystep", 1.0 / mnHeight ); + + pProgram->SetTexture("crc_table", rCRCTableTexture); + pProgram->SetTexture("sampler", rInputTexture); + pProgram->DrawTexture(rInputTexture); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + + CHECK_GL_ERROR(); + + // Second Pass + + nWidth = aFirstPassTexture.GetWidth(); + nHeight = aFirstPassTexture.GetHeight(); + + pProgram = xContext->UseProgram("textureVertexShader", FragShader); + if (pProgram == nullptr) + return false; + + nNewWidth = ceil( nWidth / 4.0 ); + nNewHeight = ceil( nHeight / 4.0 ); + + OpenGLTexture aSecondPassTexture(nNewWidth, nNewHeight); + pFramebuffer = xContext->AcquireFramebuffer(aSecondPassTexture); + + pProgram->SetUniform1f( "xstep", 1.0 / mnWidth ); + pProgram->SetUniform1f( "ystep", 1.0 / mnHeight ); + + pProgram->SetTexture("crc_table", rCRCTableTexture); + pProgram->SetTexture("sampler", aFirstPassTexture); + pProgram->DrawTexture(aFirstPassTexture); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + + CHECK_GL_ERROR(); + + // Final CRC on CPU + OpenGLTexture& aFinalTexture = aSecondPassTexture; + std::vector aBuf( aFinalTexture.GetWidth() * aFinalTexture.GetHeight() * 4 ); + aFinalTexture.Read(GL_RGBA, GL_UNSIGNED_BYTE, aBuf.data()); + + BitmapChecksum nCrc = vcl_get_checksum(0, aBuf.data(), aBuf.size()); + + rChecksum = nCrc; + return true; +} + +void OpenGLSalBitmap::updateChecksum() const +{ + if (mbChecksumValid) + return; + + if( (mnWidth * mnHeight) < (1024*768) || mnWidth < 128 || mnHeight < 128 ) + { + SalBitmap::updateChecksum(); + return; + } + + OpenGLSalBitmap* pThis = const_cast(this); + + OpenGLVCLContextZone aContextZone; + OpenGLTexture& rInputTexture = GetTexture(); + pThis->mbChecksumValid = calcChecksumGL(rInputTexture, pThis->mnChecksum); + if (!pThis->mbChecksumValid) + SalBitmap::updateChecksum(); +} + +BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( BitmapAccessMode nMode ) +{ + OpenGLVCLContextZone aContextZone; + + if( nMode != BitmapAccessMode::Info ) + { + if (!mpUserBuffer) + { + if( !AllocateUserData() ) + return nullptr; + if( maTexture && !ReadTexture() ) + { + DeallocateUserData(); + return nullptr; + } + } + } + + // mpUserBuffer must be unique when we are doing the write access + if (nMode == BitmapAccessMode::Write && mpUserBuffer && mpUserBuffer.use_count() > 1) + { + std::shared_ptr aBuffer(mpUserBuffer); + + mpUserBuffer.reset(); + AllocateUserData(); + memcpy(mpUserBuffer.get(), aBuffer.get(), mnBytesPerRow * mnHeight); + } + + BitmapBuffer* pBuffer = new BitmapBuffer; + pBuffer->mnWidth = mnWidth; + pBuffer->mnHeight = mnHeight; + pBuffer->maPalette = maPalette; + pBuffer->mnScanlineSize = mnBytesPerRow; + pBuffer->mpBits = mpUserBuffer.get(); + pBuffer->mnBitCount = mnBits; + + switch (mnBits) + { + case 1: + pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal; + break; + case 4: + pBuffer->mnFormat = ScanlineFormat::N4BitMsnPal; + break; + case 8: + pBuffer->mnFormat = ScanlineFormat::N8BitPal; + break; + case 24: + { + pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb; + break; + } + case 32: + { + pBuffer->mnFormat = ScanlineFormat::N32BitTcRgba; + ColorMaskElement aRedMask(0xff000000); + aRedMask.CalcMaskShift(); + ColorMaskElement aGreenMask(0x00ff0000); + aGreenMask.CalcMaskShift(); + ColorMaskElement aBlueMask(0x0000ff00); + aBlueMask.CalcMaskShift(); + pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask); + break; + } + default: assert(false); + } + + return pBuffer; +} + +void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) +{ + OpenGLVCLContextZone aContextZone; + + if( nMode == BitmapAccessMode::Write ) + { + maTexture = OpenGLTexture(); + mbDirtyTexture = true; + mbChecksumValid = false; + } + // The palette is modified on read during the BitmapWriteAccess, + // but of course, often it is not modified; interesting. + maPalette = pBuffer->maPalette; + + // Are there any more ground movements underneath us ? + assert( pBuffer->mnWidth == mnWidth ); + assert( pBuffer->mnHeight == mnHeight ); + assert( pBuffer->mnBitCount == mnBits ); + + delete pBuffer; +} + +bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ ) +{ + SAL_WARN( "vcl.opengl", "*** NOT IMPLEMENTED *** GetSystemData" ); +#if 0 + // TODO Implement for ANDROID/OSX/IOS/WIN32 + X11SalBitmap rBitmap; + BitmapBuffer* pBuffer; + + rBitmap.Create( GetSize(), mnBits, maPalette ); + pBuffer = rBitmap.AcquireBuffer( false ); + if( pBuffer == NULL ) + return false; + + if (!mpUserBuffer.get()) + { + if( !AllocateUserData() || !ReadTexture() ) + { + rBitmap.ReleaseBuffer( pBuffer, false ); + DeallocateUserData(); + return false; + } + } + + // TODO Might be more efficient to add a static method to SalBitmap + // to get system data from a buffer + memcpy( pBuffer->mpBits, mpUserBuffer.get(), mnBytesPerRow * mnHeight ); + + rBitmap.ReleaseBuffer( pBuffer, false ); + return rBitmap.GetSystemData( rData ); +#else + return false; +#endif +} + +bool OpenGLSalBitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) +{ + VCL_GL_INFO("::Replace"); + + OpenGLZone aZone; + rtl::Reference xContext = OpenGLContext::getVCLContext(); + xContext->state().scissor().disable(); + xContext->state().stencil().disable(); + + OpenGLFramebuffer* pFramebuffer; + OpenGLProgram* pProgram; + + GetTexture(); + pProgram = xContext->UseProgram( "textureVertexShader", + "replaceColorFragmentShader" ); + if( !pProgram ) + return false; + + OpenGLTexture aNewTex( mnWidth, mnHeight ); + pFramebuffer = xContext->AcquireFramebuffer( aNewTex ); + + pProgram->SetTexture( "sampler", maTexture ); + pProgram->SetColor( "search_color", rSearchColor ); + pProgram->SetColor( "replace_color", rReplaceColor ); + pProgram->SetUniform1f( "epsilon", nTol / 255.0f ); + pProgram->DrawTexture( maTexture ); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer( pFramebuffer ); + maTexture = aNewTex; + + CHECK_GL_ERROR(); + return true; +} + +// Convert texture to greyscale and adjust bitmap metadata +bool OpenGLSalBitmap::ConvertToGreyscale() +{ + VCL_GL_INFO("::ConvertToGreyscale"); + + // avoid re-converting to 8bits. + if ( mnBits == 8 && maPalette.IsGreyPalette8Bit()) + return true; + + OpenGLZone aZone; + rtl::Reference xContext = OpenGLContext::getVCLContext(); + xContext->state().scissor().disable(); + xContext->state().stencil().disable(); + + OpenGLFramebuffer* pFramebuffer; + OpenGLProgram* pProgram; + + GetTexture(); + pProgram = xContext->UseProgram("textureVertexShader", "greyscaleFragmentShader"); + + if (!pProgram) + return false; + + OpenGLTexture aNewTex(mnWidth, mnHeight); + pFramebuffer = xContext->AcquireFramebuffer(aNewTex); + pProgram->SetTexture("sampler", maTexture); + pProgram->DrawTexture(maTexture); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer( pFramebuffer ); + maTexture = aNewTex; + mnBits = 8; + maPalette = Bitmap::GetGreyPalette(256); + + // AllocateUserData will handle the rest. + DeallocateUserData(); + mbDirtyTexture = false; + + CHECK_GL_ERROR(); + return true; +} + +// This is needed to just make the bitmap usable as an alpha channel. +// Converting to 8bit grey will do. +bool OpenGLSalBitmap::InterpretAs8Bit() +{ + return ConvertToGreyscale(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/scale.cxx b/vcl/opengl/scale.cxx new file mode 100644 index 000000000..98f0f5ea7 --- /dev/null +++ b/vcl/opengl/scale.cxx @@ -0,0 +1,423 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +using vcl::Kernel; +using vcl::Lanczos3Kernel; + +bool OpenGLSalBitmap::ImplScaleFilter( + const rtl::Reference< OpenGLContext > &xContext, + const double& rScaleX, + const double& rScaleY, + GLenum nFilter ) +{ + OpenGLFramebuffer* pFramebuffer; + OpenGLProgram* pProgram; + GLenum nOldFilter; + int nNewWidth( mnWidth * rScaleX ); + int nNewHeight( mnHeight * rScaleY ); + + pProgram = xContext->UseProgram( "textureVertexShader", + "textureFragmentShader" ); + if( !pProgram ) + return false; + + OpenGLTexture aNewTex(nNewWidth, nNewHeight); + pFramebuffer = xContext->AcquireFramebuffer( aNewTex ); + + pProgram->SetTexture( "sampler", maTexture ); + nOldFilter = maTexture.GetFilter(); + maTexture.SetFilter( nFilter ); + pProgram->ApplyMatrix(mnWidth, mnHeight); + pProgram->DrawTexture( maTexture ); + maTexture.SetFilter( nOldFilter ); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer( pFramebuffer ); + + mnWidth = nNewWidth; + mnHeight = nNewHeight; + maTexture = aNewTex; + + CHECK_GL_ERROR(); + return true; +} + +void OpenGLSalBitmap::ImplCreateKernel( + const double& fScale, + const Kernel& rKernel, + GLfloat*& pWeights, + sal_uInt32& aKernelSize ) +{ + const double fSamplingRadius(rKernel.GetWidth()); + const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius); + const double fFilterFactor(std::min(fScale, 1.0)); + int aNumberOfContributions; + double aSum( 0 ); + + aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1 - 6; + aKernelSize = aNumberOfContributions / 2 + 1; + + // avoid a crash for now; re-think me. + if (aKernelSize > 16) + aKernelSize = 16; + + pWeights = new GLfloat[16]; + memset( pWeights, 0, 16 * sizeof( GLfloat ) ); + + for( sal_uInt32 i(0); i < aKernelSize; i++ ) + { + const GLfloat aWeight( rKernel.Calculate( fFilterFactor * i ) ); + if( fabs( aWeight ) >= 0.0001 ) + { + pWeights[i] = aWeight; + aSum += i > 0 ? aWeight * 2 : aWeight; + } + } + + for( sal_uInt32 i(0); i < aKernelSize; i++ ) + { + pWeights[i] /= aSum; + } +} + +bool OpenGLSalBitmap::ImplScaleConvolution( + const rtl::Reference< OpenGLContext > &xContext, + const double& rScaleX, + const double& rScaleY, + const Kernel& aKernel ) +{ + OpenGLFramebuffer* pFramebuffer; + OpenGLProgram* pProgram; + GLfloat* pWeights( nullptr ); + sal_uInt32 nKernelSize; + GLfloat aOffsets[32]; + int nNewWidth( mnWidth * rScaleX ); + int nNewHeight( mnHeight * rScaleY ); + + // TODO Make sure the framebuffer is alright + + pProgram = xContext->UseProgram( "textureVertexShader", + "convolutionFragmentShader" ); + if( pProgram == nullptr ) + return false; + + // horizontal scaling in scratch texture + if( mnWidth != nNewWidth ) + { + OpenGLTexture aScratchTex(nNewWidth, nNewHeight); + + pFramebuffer = xContext->AcquireFramebuffer( aScratchTex ); + + for( sal_uInt32 i = 0; i < 16; i++ ) + { + aOffsets[i * 2] = i / static_cast(mnWidth); + aOffsets[i * 2 + 1] = 0; + } + ImplCreateKernel( rScaleX, aKernel, pWeights, nKernelSize ); + pProgram->SetUniform1fv( "kernel", 16, pWeights ); + pProgram->SetUniform2fv( "offsets", 16, aOffsets ); + pProgram->SetTexture( "sampler", maTexture ); + pProgram->DrawTexture( maTexture ); + pProgram->Clean(); + + maTexture = aScratchTex; + OpenGLContext::ReleaseFramebuffer( pFramebuffer ); + } + + // vertical scaling in final texture + if( mnHeight != nNewHeight ) + { + OpenGLTexture aScratchTex(nNewWidth, nNewHeight); + + pFramebuffer = xContext->AcquireFramebuffer( aScratchTex ); + + for( sal_uInt32 i = 0; i < 16; i++ ) + { + aOffsets[i * 2] = 0; + aOffsets[i * 2 + 1] = i / static_cast(mnHeight); + } + ImplCreateKernel( rScaleY, aKernel, pWeights, nKernelSize ); + pProgram->SetUniform1fv( "kernel", 16, pWeights ); + pProgram->SetUniform2fv( "offsets", 16, aOffsets ); + pProgram->SetTexture( "sampler", maTexture ); + pProgram->DrawTexture( maTexture ); + pProgram->Clean(); + + maTexture = aScratchTex; + OpenGLContext::ReleaseFramebuffer( pFramebuffer ); + } + + mnWidth = nNewWidth; + mnHeight = nNewHeight; + + CHECK_GL_ERROR(); + return true; +} + +/* + "Area" scaling algorithm, which seems to give better results for downscaling + than other algorithms. The principle (taken from opencv, see resize.cl) + is that each resulting pixel is the average of all the source pixel values + it represents. Which is trivial in the case of exact multiples for downscaling, + the generic case needs to also consider that some source pixels contribute + only partially to their resulting pixels (because of non-integer multiples). +*/ +bool OpenGLSalBitmap::ImplScaleArea( const rtl::Reference< OpenGLContext > &xContext, + double rScaleX, double rScaleY ) +{ + int nNewWidth( mnWidth * rScaleX ); + int nNewHeight( mnHeight * rScaleY ); + + if( nNewWidth == mnWidth && nNewHeight == mnHeight ) + return true; + + double ixscale = 1 / rScaleX; + double iyscale = 1 / rScaleY; + bool fast = ( ixscale == std::trunc( ixscale ) && iyscale == std::trunc( iyscale ) + && int( nNewWidth * ixscale ) == mnWidth && int( nNewHeight * iyscale ) == mnHeight ); + + bool bTwoPasses = false; + + // The generic case has arrays only up to 100 ratio downscaling, which is hopefully enough + // in practice, but protect against buffer overflows in case such an extreme case happens + // (and in such case the precision of the generic algorithm probably doesn't matter anyway). + if( ixscale > 100 || iyscale > 100 ) + { + fast = true; + } + else + { + if (ixscale > 16 || iyscale > 16) + { + ixscale = std::floor(std::sqrt(ixscale)); + iyscale = std::floor(std::sqrt(iyscale)); + nNewWidth = int(mnWidth / ixscale); + rScaleX *= ixscale; // second pass x-scale factor + nNewHeight = int(mnHeight / iyscale); + rScaleY *= iyscale; // second pass y-scale factor + bTwoPasses = true; + } + } + + // TODO Make sure the framebuffer is alright + + OString sUseReducedRegisterVariantDefine; + if (xContext->getOpenGLCapabilitySwitch().mbLimitedShaderRegisters) + sUseReducedRegisterVariantDefine = OString("#define USE_REDUCED_REGISTER_VARIANT\n"); + + OpenGLProgram* pProgram = xContext->UseProgram( "textureVertexShader", + fast ? OUString( "areaScaleFastFragmentShader" ) : OUString( "areaScaleFragmentShader" ), + sUseReducedRegisterVariantDefine); + + if( pProgram == nullptr ) + return false; + + OpenGLTexture aScratchTex(nNewWidth, nNewHeight); + + OpenGLFramebuffer* pFramebuffer = xContext->AcquireFramebuffer( aScratchTex ); + + // NOTE: This setup is also done in OpenGLSalGraphicsImpl::DrawTransformedTexture(). + if( fast ) + { + pProgram->SetUniform1i( "xscale", ixscale ); + pProgram->SetUniform1i( "yscale", iyscale ); + // The shader operates on pixels in the surrounding area, so it's necessary + // to know the step in texture coordinates to get to the next pixel. + // With a texture atlas the "texture" is just a subtexture of a larger texture, + // so while with a normal texture we'd map between <0.0,1.0> and <0,mnWidth>, + // with a subtexture the texture coordinates range is smaller. + GLfloat srcCoords[ 8 ]; + maTexture.GetWholeCoord( srcCoords ); + pProgram->SetUniform1f( "xstep", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / mnWidth ); + pProgram->SetUniform1f( "ystep", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / mnHeight ); + pProgram->SetUniform1f( "ratio", 1.0 / ( ixscale * iyscale )); + } + else + { + pProgram->SetUniform1f( "xscale", ixscale ); + pProgram->SetUniform1f( "yscale", iyscale ); + pProgram->SetUniform1i( "swidth", mnWidth ); + pProgram->SetUniform1i( "sheight", mnHeight ); + // The shader internally actually operates on pixel coordinates, + // so it needs to know how to convert to those from the texture coordinates. + // With a simple texture that would mean converting e.g. between + // <0,mnWidth-1> and <0.0,1.0> coordinates. + // However with a texture atlas the "texture" is just a subtexture + // of a larger texture, so the texture coordinates need offset and ratio + // conversion too. + GLfloat srcCoords[ 8 ]; + maTexture.GetWholeCoord( srcCoords ); + pProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] ); + pProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] ); + pProgram->SetUniform1f( "xtopixelratio", nNewWidth / ( srcCoords[ 4 ] - srcCoords[ 0 ] )); + pProgram->SetUniform1f( "ytopixelratio", nNewHeight / ( srcCoords[ 5 ] - srcCoords[ 1 ] )); + pProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / mnWidth ); + pProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / mnHeight ); + } + + pProgram->SetTexture( "sampler", maTexture ); + pProgram->DrawTexture( maTexture ); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + + CHECK_GL_ERROR(); + + if (bTwoPasses) + { + mnWidth = nNewWidth; + mnHeight = nNewHeight; + + nNewWidth = round(mnWidth * rScaleX); + nNewHeight = round(mnHeight * rScaleY); + + ixscale = 1 / rScaleX; + iyscale = 1 / rScaleY; + + pProgram = xContext->UseProgram("textureVertexShader", "areaScaleFragmentShader", sUseReducedRegisterVariantDefine); + if (pProgram == nullptr) + return false; + + OpenGLTexture aScratchTex2(nNewWidth, nNewHeight); + + pFramebuffer = xContext->AcquireFramebuffer(aScratchTex2); + + pProgram->SetUniform1f("xscale", ixscale); + pProgram->SetUniform1f("yscale", iyscale); + pProgram->SetUniform1i("swidth", mnWidth); + pProgram->SetUniform1i("sheight", mnHeight); + + GLfloat srcCoords[ 8 ]; + aScratchTex.GetWholeCoord( srcCoords ); + pProgram->SetUniform1f( "xoffset", srcCoords[ 0 ] ); + pProgram->SetUniform1f( "yoffset", srcCoords[ 1 ] ); + pProgram->SetUniform1f( "xtopixelratio", nNewWidth / ( srcCoords[ 4 ] - srcCoords[ 0 ] )); + pProgram->SetUniform1f( "ytopixelratio", nNewHeight / ( srcCoords[ 5 ] - srcCoords[ 1 ] )); + pProgram->SetUniform1f( "xfrompixelratio", ( srcCoords[ 4 ] - srcCoords[ 0 ] ) / mnWidth ); + pProgram->SetUniform1f( "yfrompixelratio", ( srcCoords[ 5 ] - srcCoords[ 1 ] ) / mnHeight ); + + pProgram->SetTexture("sampler", aScratchTex); + pProgram->DrawTexture(aScratchTex); + pProgram->Clean(); + + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + + CHECK_GL_ERROR(); + + maTexture = aScratchTex2; + mnWidth = nNewWidth; + mnHeight = nNewHeight; + } + else + { + maTexture = aScratchTex; + mnWidth = nNewWidth; + mnHeight = nNewHeight; + } + + return true; +} + +void OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) +{ + VCL_GL_INFO( "::ImplScale" ); + + mpUserBuffer.reset(); + OpenGLVCLContextZone aContextZone; + rtl::Reference xContext = OpenGLContext::getVCLContext(); + xContext->state().scissor().disable(); + xContext->state().stencil().disable(); + + if (rScaleX <= 1 && rScaleY <= 1) + { + nScaleFlag = BmpScaleFlag::BestQuality; + } + + if( nScaleFlag == BmpScaleFlag::Fast ) + { + ImplScaleFilter( xContext, rScaleX, rScaleY, GL_NEAREST ); + } + else if( nScaleFlag == BmpScaleFlag::BiLinear ) + { + ImplScaleFilter( xContext, rScaleX, rScaleY, GL_LINEAR ); + } + else if( nScaleFlag == BmpScaleFlag::Default ) + { + const Lanczos3Kernel aKernel; + + ImplScaleConvolution( xContext, rScaleX, rScaleY, aKernel ); + } + else if( nScaleFlag == BmpScaleFlag::BestQuality && rScaleX <= 1 && rScaleY <= 1 ) + { // Use area scaling for best quality, but only if downscaling. + ImplScaleArea( xContext, rScaleX, rScaleY ); + } + else if( nScaleFlag == BmpScaleFlag::Lanczos || nScaleFlag == BmpScaleFlag::BestQuality ) + { + const Lanczos3Kernel aKernel; + + ImplScaleConvolution( xContext, rScaleX, rScaleY, aKernel ); + } + else + SAL_WARN( "vcl.opengl", "Invalid flag for scaling operation" ); +} + +bool OpenGLSalBitmap::ScalingSupported() const +{ + return true; +} + +bool OpenGLSalBitmap::Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) +{ + OpenGLVCLContextZone aContextZone; + + VCL_GL_INFO("::Scale " << int(nScaleFlag) + << " from " << mnWidth << "x" << mnHeight + << " to " << (mnWidth * rScaleX) << "x" << (mnHeight * rScaleY) ); + + if( nScaleFlag == BmpScaleFlag::Fast || + nScaleFlag == BmpScaleFlag::BiLinear || + nScaleFlag == BmpScaleFlag::Lanczos || + nScaleFlag == BmpScaleFlag::Default || + nScaleFlag == BmpScaleFlag::BestQuality ) + { + ImplScale( rScaleX, rScaleY, nScaleFlag ); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/areaHashCRC64TFragmentShader.glsl b/vcl/opengl/shaders/areaHashCRC64TFragmentShader.glsl new file mode 100644 index 000000000..901b481d8 --- /dev/null +++ b/vcl/opengl/shaders/areaHashCRC64TFragmentShader.glsl @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* TODO Use textureOffset for newest version of GLSL */ + + +#version 130 + +uniform sampler2D crc_table; +uniform sampler2D sampler; +uniform float xstep; +uniform float ystep; + +varying vec2 tex_coord; + +const int scale = 4; +const float ratio = 16.0; + + +ivec2 crc64( ivec2 hval, int color ) +{ + int dx = 2 * ((hval[0] ^ color) & 0xff); + float s = dx / 255.0; + vec4 table_value_lo = round(texture2D( crc_table, vec2( s, 0.0 ) ) * 255.0); + s = (dx+1) / 255.0; + vec4 table_value_hi = round(texture2D( crc_table, vec2( s, 0.0 ) ) * 255.0); + + int tvalue_lo = int(table_value_lo[0]) | (int(table_value_lo[1]) << 8) | (int(table_value_lo[2]) << 16) | (int(table_value_lo[3]) << 24); + int tvalue_hi = int(table_value_hi[0]) | (int(table_value_hi[1]) << 8) | (int(table_value_hi[2]) << 16) | (int(table_value_hi[3]) << 24); + + hval[1] = tvalue_hi ^ (hval[1] >> 8); + hval[0] = tvalue_lo ^ ( (hval[1] << 24) | (hval[0] >> 8) ); + + return hval; +} + + +void main(void) +{ + ivec2 Crc = ivec2( 0xffffffff, 0xffffffff ); + vec2 offset = vec2( 0.0, 0.0 ); + vec2 next_coord = tex_coord.st; + for( int y = 0; y < scale && next_coord.y <= 1.0; ++y ) + { + for( int x = 0; x < scale && next_coord.x <= 1.0; ++x ) + { + vec4 pixel = round(texture2D( sampler, next_coord ) * 255.0); + + int r = int(pixel.r); // 0..255 + int g = int(pixel.g); // 0..255 + int b = int(pixel.b); // 0..255 + int a = int(pixel.a); // 0..255 + + Crc = crc64( Crc, r ); + Crc = crc64( Crc, g ); + Crc = crc64( Crc, b ); + Crc = crc64( Crc, a ); + + offset.x += xstep; + next_coord = tex_coord.st + offset; + } + offset.y += ystep; + offset.x = 0.0; + next_coord = tex_coord.st + offset; + } + + Crc[0] = ~Crc[0]; + Crc[1] = ~Crc[1]; + + int Hash = Crc[0] ^ Crc[1]; + + float fr = ( Hash & 0xff) / 255.0; + float fg = ((Hash >> 8) & 0xff) / 255.0; + float fb = ((Hash >> 16) & 0xff) / 255.0; + float fa = ((Hash >> 24) & 0xff) / 255.0; + + + gl_FragColor = vec4(fr, fg, fb, fa); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/areaScaleFastFragmentShader.glsl b/vcl/opengl/shaders/areaScaleFastFragmentShader.glsl new file mode 100644 index 000000000..57ad8fa97 --- /dev/null +++ b/vcl/opengl/shaders/areaScaleFastFragmentShader.glsl @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* TODO Use textureOffset for newest version of GLSL */ + +#version 130 + +uniform sampler2D sampler; +uniform int xscale; +uniform int yscale; +uniform float xstep; +uniform float ystep; +uniform float ratio; // = 1.0/(xscale*yscale) + +varying vec2 tex_coord; + +// This mode makes the scaling work like maskedTextureFragmentShader.glsl +// (instead of like plain textureVertexShader.glsl). +#ifdef MASKED +varying vec2 mask_coord; +uniform sampler2D mask; +#endif + +/* + Just make the resulting color the average of all the source pixels + (which is an area (xscale)x(yscale) ). +*/ +void main(void) +{ + vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 ); + vec2 offset = vec2( 0.0, 0.0 ); + for( int y = 0; y < yscale; ++y ) + { + for( int x = 0; x < xscale; ++x ) + { +#ifndef MASKED + sum += texture2D( sampler, tex_coord.st + offset ); +#else + vec4 texel; + texel = texture2D( sampler, tex_coord.st + offset ); + texel.a = 1.0 - texture2D( mask, mask_coord.st + offset ).r; + sum += texel; +#endif + offset.x += xstep; + } + offset.y += ystep; + offset.x = 0.0; + } + sum *= ratio; + gl_FragColor = sum; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/areaScaleFragmentShader.glsl b/vcl/opengl/shaders/areaScaleFragmentShader.glsl new file mode 100644 index 000000000..5dab5ba01 --- /dev/null +++ b/vcl/opengl/shaders/areaScaleFragmentShader.glsl @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +uniform sampler2D sampler; +uniform int swidth; +uniform int sheight; +uniform float xscale; +uniform float yscale; +uniform float xoffset; +uniform float yoffset; +uniform float xfrompixelratio; +uniform float yfrompixelratio; +uniform float xtopixelratio; +uniform float ytopixelratio; + +varying vec2 tex_coord; + +// This mode makes the scaling work like maskedTextureFragmentShader.glsl +// (instead of like plain textureVertexShader.glsl). +#ifdef MASKED +varying vec2 mask_coord; +uniform sampler2D mask; +#endif + +#ifdef USE_REDUCED_REGISTER_VARIANT + +vec4 getTexel(int x, int y) +{ + vec2 pos = vec2( x * xfrompixelratio + xoffset, y * yfrompixelratio + yoffset ); + vec4 texel = texture2D(sampler, pos); +#ifdef MASKED + texel.a = 1.0 - texture2D(mask, pos - tex_coord.st + mask_coord.st).r; +#endif + return texel; +} + +void main(void) +{ + // Convert to pixel coordinates again. + int dx = int(( tex_coord.s - xoffset ) * xtopixelratio ); + int dy = int(( tex_coord.t - yoffset ) * ytopixelratio ); + + // Compute the range of source pixels which will make up this destination pixel. + float fsx1 = min(dx * xscale, float(swidth - 1)); + float fsx2 = min(fsx1 + xscale, float(swidth - 1)); + + float fsy1 = min(dy * yscale, float(sheight - 1)); + float fsy2 = min(fsy1 + yscale, float(sheight - 1)); + + // To whole pixel coordinates. + int xstart = int(floor(fsx1)); + int xend = int(floor(fsx2)); + + int ystart = int(floor(fsy1)); + int yend = int(floor(fsy2)); + + float xlength = fsx2 - fsx1; + float ylength = fsy2 - fsy1; + + float xContribution[3]; + xContribution[0] = (1.0 - max(0.0, fsx1 - xstart)) / xlength; + xContribution[1] = 1.0 / xlength; + xContribution[2] = (1.0 - max(0.0, (xend + 1) - fsx2)) / xlength; + + float yContribution[3]; + yContribution[0] = (1.0 - max(0.0, fsy1 - ystart)) / ylength; + yContribution[1] = 1.0 / ylength; + yContribution[2] = (1.0 - max(0.0, (yend + 1) - fsy2)) / ylength; + + vec4 sumAll = vec4(0.0, 0.0, 0.0, 0.0); + vec4 texel; + // First Y pass + { + vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0); + + sumX += getTexel(xstart, ystart) * xContribution[0]; + for (int x = xstart + 1; x < xend; ++x) + { + sumX += getTexel(x, ystart) * xContribution[1]; + } + sumX += getTexel(xend, ystart) * xContribution[2]; + + sumAll += sumX * yContribution[0]; + } + + // Middle Y Passes + for (int y = ystart + 1; y < yend; ++y) + { + vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0); + + sumX += getTexel(xstart, y) * xContribution[0]; + for (int x = xstart + 1; x < xend; ++x) + { + sumX += getTexel(x, y) * xContribution[1]; + } + sumX += getTexel(xend, y) * xContribution[2]; + + sumAll += sumX * yContribution[1]; + } + + // Last Y pass + { + vec4 sumX = vec4(0.0, 0.0, 0.0, 0.0); + + sumX += getTexel(xstart, yend) * xContribution[0]; + for (int x = xstart + 1; x < xend; ++x) + { + sumX += getTexel(x, yend) * xContribution[1]; + } + sumX += getTexel(xend, yend) * xContribution[2]; + + sumAll += sumX * yContribution[2]; + } + + gl_FragColor = sumAll; +} +#else +void main(void) +{ + // Convert to pixel coordinates again. + int dx = int(( tex_coord.s - xoffset ) * xtopixelratio ); + int dy = int(( tex_coord.t - yoffset ) * ytopixelratio ); + + // How much each column/row will contribute to the resulting pixel. + // Note: These values are always the same for the same X (or Y), + // so they could be precalculated in C++ and passed to the shader, + // but GLSL has limits on the size of uniforms passed to it, + // so it'd need something like texture buffer objects from newer + // GLSL versions, and it seems the hassle is not really worth it. + float xratio[ 16 + 2 ]; + float yratio[ 16 + 2 ]; + + // For finding the first and last source pixel. + int xpixel[ 16 + 2 ]; + int ypixel[ 16 + 2 ]; + + int xpos = 0; + int ypos = 0; + + // Compute the range of source pixels which will make up this destination pixel. + float fsx1 = dx * xscale; + float fsx2 = fsx1 + xscale; + // To whole pixel coordinates. + int sx1 = int( ceil( fsx1 ) ); + int sx2 = int( floor( fsx2 ) ); + // Range checking. + sx2 = min( sx2, swidth - 1 ); + sx1 = min( sx1, sx2 ); + + // How much one full column contributes to the resulting pixel. + float width = min( xscale, swidth - fsx1 ); + + if( sx1 - fsx1 > 0.001 ) + { // The first column contributes only partially. + xpixel[ xpos ] = sx1 - 1; + xratio[ xpos ] = ( sx1 - fsx1 ) / width; + ++xpos; + } + for( int sx = sx1; sx < sx2; ++sx ) + { // Columns that fully contribute to the resulting pixel. + xpixel[ xpos ] = sx; + xratio[ xpos ] = 1.0 / width; + ++xpos; + } + if( fsx2 - sx2 > 0.001 ) + { // The last column contributes only partially. + xpixel[ xpos ] = sx2; + xratio[ xpos ] = min( min( fsx2 - sx2, 1.0 ) / width, 1.0 ); + ++xpos; + } + + // The same for Y. + float fsy1 = dy * yscale; + float fsy2 = fsy1 + yscale; + int sy1 = int( ceil( fsy1 ) ); + int sy2 = int( floor( fsy2 ) ); + sy2 = min( sy2, sheight - 1 ); + sy1 = min( sy1, sy2 ); + + float height = min( yscale, sheight - fsy1 ); + + if( sy1 - fsy1 > 0.001 ) + { + ypixel[ ypos ] = sy1 - 1; + yratio[ ypos ] = ( sy1 - fsy1 ) / height; + ++ypos; + } + for( int sy = sy1; sy < sy2; ++sy ) + { + ypixel[ ypos ] = sy; + yratio[ ypos ] = 1.0 / height; + ++ypos; + } + if( fsy2 - sy2 > 0.001 ) + { + ypixel[ ypos ] = sy2; + yratio[ ypos ] = min( min( fsy2 - sy2, 1.0 ) / height, 1.0 ); + ++ypos; + } + + int xstart = xpixel[ 0 ]; + int xend = xpixel[ xpos - 1 ]; + int ystart = ypixel[ 0 ]; + int yend = ypixel[ ypos - 1 ]; + + vec4 sum = vec4( 0.0, 0.0, 0.0, 0.0 ); + + ypos = 0; + for( int y = ystart; y <= yend; ++y, ++ypos ) + { + vec4 tmp = vec4( 0.0, 0.0, 0.0, 0.0 ); + xpos = 0; + for( int x = xstart; x <= xend; ++x, ++xpos ) + { + vec2 pos = vec2( x * xfrompixelratio + xoffset, y * yfrompixelratio + yoffset ); +#ifndef MASKED + tmp += texture2D( sampler, pos ) * xratio[ xpos ]; +#else + vec4 texel; + texel = texture2D( sampler, pos ); + texel.a = 1.0 - texture2D( mask, pos - tex_coord.st + mask_coord.st ).r; + tmp += texel * xratio[ xpos ]; +#endif + } + sum += tmp * yratio[ ypos ]; + } + + gl_FragColor = sum; +} +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/blendedTextureFragmentShader.glsl b/vcl/opengl/shaders/blendedTextureFragmentShader.glsl new file mode 100644 index 000000000..15dfcf7e7 --- /dev/null +++ b/vcl/opengl/shaders/blendedTextureFragmentShader.glsl @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying vec2 tex_coord; +varying vec2 alpha_coord; +varying vec2 mask_coord; + +uniform sampler2D sampler; +uniform sampler2D mask; +uniform sampler2D alpha; + +void main() +{ + vec4 texel0, texel1, texel2; + + texel0 = texture2D(sampler, tex_coord); + texel1 = texture2D(mask, mask_coord); + texel2 = texture2D(alpha, alpha_coord); + gl_FragColor = texel0; + + /* Only blend if the alpha texture wasn't fully transparent */ + gl_FragColor.a = 1.0 - (1.0 - floor(texel2.r)) * texel1.r; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/blendedTextureVertexShader.glsl b/vcl/opengl/shaders/blendedTextureVertexShader.glsl new file mode 100644 index 000000000..3e60d0e22 --- /dev/null +++ b/vcl/opengl/shaders/blendedTextureVertexShader.glsl @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +attribute vec2 tex_coord_in; +attribute vec2 alpha_coord_in; +attribute vec2 mask_coord_in; +varying vec2 tex_coord; +varying vec2 alpha_coord; +varying vec2 mask_coord; +uniform mat4 mvp; + +void main() { + gl_Position = mvp * position; + tex_coord = tex_coord_in; + alpha_coord = alpha_coord_in; + mask_coord = mask_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/combinedFragmentShader.glsl b/vcl/opengl/shaders/combinedFragmentShader.glsl new file mode 100644 index 000000000..2515b174f --- /dev/null +++ b/vcl/opengl/shaders/combinedFragmentShader.glsl @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying float fade_factor; // 0->1 fade factor used for AA +varying float multiply; + +#ifdef USE_VERTEX_COLORS +varying vec4 vertex_color; +#endif + +uniform vec4 color; + +#define TYPE_NORMAL 0 +#define TYPE_LINE 1 + +uniform int type; + +void main() +{ +#ifdef USE_VERTEX_COLORS + vec4 result = vertex_color; +#else + vec4 result = color; +#endif + + if (type == TYPE_LINE) + { + float dist = (1.0 - abs(fade_factor)) * multiply; + float alpha = clamp(dist, 0.0, 1.0); + result.a = result.a * alpha; + } + + gl_FragColor = result; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/combinedTextureFragmentShader.glsl b/vcl/opengl/shaders/combinedTextureFragmentShader.glsl new file mode 100644 index 000000000..2990de8c4 --- /dev/null +++ b/vcl/opengl/shaders/combinedTextureFragmentShader.glsl @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying vec2 tex_coord; +varying vec2 alpha_coord; +varying vec2 mask_coord; +#ifdef USE_VERTEX_COLORS +varying vec4 vertex_color; +#endif + +uniform sampler2D texture; +uniform sampler2D mask; +uniform sampler2D alpha; + +uniform vec4 color; + +uniform int type; + +#define TYPE_NORMAL 0 +#define TYPE_BLEND 1 +#define TYPE_MASKED 2 +#define TYPE_DIFF 3 +#define TYPE_MASKED_COLOR 4 + +void main() +{ + vec4 texelTexture = texture2D(texture, tex_coord); + + if (type == TYPE_NORMAL) + { + gl_FragColor = texelTexture; + } + else if (type == TYPE_BLEND) + { + vec4 texelMask = texture2D(mask, mask_coord); + vec4 texelAlpha = texture2D(alpha, alpha_coord); + gl_FragColor = texelTexture; + gl_FragColor.a = 1.0 - (1.0 - floor(texelAlpha.r)) * texelMask.r; + } + else if (type == TYPE_MASKED) + { + vec4 texelMask = texture2D(mask, mask_coord); + gl_FragColor = texelTexture; + gl_FragColor.a = 1.0 - texelMask.r; + } + else if (type == TYPE_DIFF) + { + vec4 texelMask = texture2D(mask, mask_coord); + float alpha = 1.0 - abs(texelTexture.r - texelMask.r); + if (alpha > 0.0) + gl_FragColor = texelMask / alpha; + gl_FragColor.a = alpha; + } + else if (type == TYPE_MASKED_COLOR) + { +#ifdef USE_VERTEX_COLORS + gl_FragColor = vertex_color; +#else + gl_FragColor = color; +#endif + gl_FragColor.a = 1.0 - texelTexture.r; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/combinedTextureVertexShader.glsl b/vcl/opengl/shaders/combinedTextureVertexShader.glsl new file mode 100644 index 000000000..52d44d553 --- /dev/null +++ b/vcl/opengl/shaders/combinedTextureVertexShader.glsl @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +attribute vec2 tex_coord_in; +attribute vec2 mask_coord_in; +attribute vec2 alpha_coord_in; +#ifdef USE_VERTEX_COLORS +attribute vec4 vertex_color_in; +#endif + +varying vec2 tex_coord; +varying vec2 mask_coord; +varying vec2 alpha_coord; +#ifdef USE_VERTEX_COLORS +varying vec4 vertex_color; +#endif + +uniform mat4 mvp; +uniform mat4 transform; + +uniform int type; + +void main() +{ + gl_Position = mvp * transform * position; + tex_coord = tex_coord_in; + mask_coord = mask_coord_in; + alpha_coord = alpha_coord_in; +#ifdef USE_VERTEX_COLORS + vertex_color = vertex_color_in / 255.0; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/combinedVertexShader.glsl b/vcl/opengl/shaders/combinedVertexShader.glsl new file mode 100644 index 000000000..16fc4a942 --- /dev/null +++ b/vcl/opengl/shaders/combinedVertexShader.glsl @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec2 position; +attribute vec4 extrusion_vectors; +#ifdef USE_VERTEX_COLORS +attribute vec4 vertex_color_in; +#endif + +varying float fade_factor; // fade factor for anti-aliasing +varying float multiply; + +#ifdef USE_VERTEX_COLORS +varying vec4 vertex_color; +#endif + +uniform float line_width; +uniform float feather; // width where we fade the line + +uniform mat4 mvp; + +#define TYPE_NORMAL 0 +#define TYPE_LINE 1 + +uniform int type; + +void main() +{ + vec2 extrusion_vector = extrusion_vectors.xy; + + float render_thickness = 0.0; + + if (type == TYPE_LINE) + { + // miter factor to additionally lengthen the distance of vertex (needed for miter) + // if 1.0 - miter_factor has no effect + float miter_factor = 1.0 / abs(extrusion_vectors.z); + // fade factor is always -1.0 or 1.0 -> we transport that info together with length + fade_factor = sign(extrusion_vectors.z); +#ifdef USE_VERTEX_COLORS + float the_feather = (1.0 + sign(extrusion_vectors.w)) / 4.0; + float the_line_width = abs(extrusion_vectors.w); +#else + float the_feather = feather; + float the_line_width = line_width; +#endif + render_thickness = (the_line_width * miter_factor + the_feather * 2.0 * miter_factor); + + // Calculate the multiplier so we can transform the 0->1 fade factor + // to take feather and line width into account. + + float start = mix(0.0, (the_line_width / 2.0) - the_feather, the_feather * 2.0); + float end = mix(1.0, (the_line_width / 2.0) + the_feather, the_feather * 2.0); + + multiply = 1.0 / (1.0 - (start / end)); + } + + // lengthen the vertex in direction of the extrusion vector by line width. + vec4 final_position = vec4(position + (extrusion_vector * (render_thickness / 2.0) ), 0.0, 1.0); + + gl_Position = mvp * final_position; + +#ifdef USE_VERTEX_COLORS + vertex_color = vertex_color_in / 255.0; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/convolutionFragmentShader.glsl b/vcl/opengl/shaders/convolutionFragmentShader.glsl new file mode 100644 index 000000000..4b2f316e0 --- /dev/null +++ b/vcl/opengl/shaders/convolutionFragmentShader.glsl @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* TODO Use textureOffset for newest version of GLSL */ + +#version 130 + +uniform sampler2D sampler; +uniform vec2 offsets[16]; +uniform float kernel[16]; + +varying vec2 tex_coord; + +void main(void) +{ + vec4 sum = texture2D(sampler, tex_coord.st) * kernel[0]; + for (int i = 1; i < 16; i++) { + sum += texture2D(sampler, tex_coord.st - offsets[i]) * kernel[i]; + sum += texture2D(sampler, tex_coord.st + offsets[i]) * kernel[i]; + } + gl_FragColor = sum; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/diffTextureFragmentShader.glsl b/vcl/opengl/shaders/diffTextureFragmentShader.glsl new file mode 100644 index 000000000..8c50ddf98 --- /dev/null +++ b/vcl/opengl/shaders/diffTextureFragmentShader.glsl @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +/*precision mediump float;*/ +varying vec2 tex_coord; +varying vec2 mask_coord; +uniform sampler2D texture; /* white background */ +uniform sampler2D mask; /* black background */ + +void main() +{ + float alpha; + vec4 texel0, texel1; + texel0 = texture2D(texture, tex_coord); + texel1 = texture2D(mask, mask_coord); + alpha = 1.0 - abs(texel0.r - texel1.r); + if(alpha > 0.0) + gl_FragColor = texel1 / alpha; + gl_FragColor.a = alpha; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/dumbVertexShader.glsl b/vcl/opengl/shaders/dumbVertexShader.glsl new file mode 100644 index 000000000..80341b614 --- /dev/null +++ b/vcl/opengl/shaders/dumbVertexShader.glsl @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +uniform mat4 mvp; + +void main() { + gl_Position = mvp * position; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/greyscaleFragmentShader.glsl b/vcl/opengl/shaders/greyscaleFragmentShader.glsl new file mode 100644 index 000000000..c37f0d5df --- /dev/null +++ b/vcl/opengl/shaders/greyscaleFragmentShader.glsl @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying vec2 tex_coord; +uniform sampler2D sampler; + +void main() { + vec4 texel = texture2D(sampler, tex_coord); + gl_FragColor = vec4(vec3(dot(texel.rgb, vec3(0.301, 0.591, 0.108))), 1.0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/invert50FragmentShader.glsl b/vcl/opengl/shaders/invert50FragmentShader.glsl new file mode 100644 index 000000000..9222888f0 --- /dev/null +++ b/vcl/opengl/shaders/invert50FragmentShader.glsl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +/*precision mediump float;*/ + +void main() { + vec2 tex_mod = mod(gl_FragCoord, 2).xy; + bool bLeft = (tex_mod.x > 0.0) && (tex_mod.x < 1.0); + bool bTop = (tex_mod.y > 0.0) && (tex_mod.y < 1.0); + // horrors - where is the XOR operator ? + if ((bTop && bLeft) || (!bTop && !bLeft)) + gl_FragColor = vec4(255,255,255,0); + else + gl_FragColor = vec4(0,0,0,0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/lineFragmentShader.glsl b/vcl/opengl/shaders/lineFragmentShader.glsl new file mode 100644 index 000000000..c49570be3 --- /dev/null +++ b/vcl/opengl/shaders/lineFragmentShader.glsl @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying float fade_factor; // 0->1 fade factor used for AA +uniform vec4 color; + +uniform float line_width; +uniform float feather; + +void main() +{ + float start = (line_width / 2.0) - feather; // where we start to apply alpha + float end = (line_width / 2.0) + feather; // where we end to apply alpha + + // Calculate the multiplier so we can transform the 0->1 fade factor + // to take feather and line width into account. + float multiplied = 1.0 / (1.0 - (start / end)); + + float dist = (1.0 - abs(fade_factor)) * multiplied; + + float alpha = clamp(dist, 0.0, 1.0); + + // modify the alpha channel only + vec4 result_color = color; + result_color.a = result_color.a * alpha; + + gl_FragColor = result_color; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/lineVertexShader.glsl b/vcl/opengl/shaders/lineVertexShader.glsl new file mode 100644 index 000000000..e26be78d0 --- /dev/null +++ b/vcl/opengl/shaders/lineVertexShader.glsl @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +attribute vec2 position; +attribute vec4 extrusion_vectors; + +varying float fade_factor; // fade factor for anti-aliasing + +uniform float line_width; +uniform float feather; // width where we fade the line + +uniform mat4 mvp; + +void main() +{ + vec2 extrusion_vector = extrusion_vectors.xy; + // miter factor to additionally lengthen the distance of vertex (needed for miter) + // if 1.0 - miter_factor has no effect + float miter_factor = 1.0f / abs(extrusion_vectors.z); + // fade factor is always -1.0 or 1.0 -> we transport that info together with length + fade_factor = sign(extrusion_vectors.z); + + float rendered_thickness = (line_width + feather * 2.0) * miter_factor; + + // lengthen the vertex in direction of the extrusion vector by line width. + vec4 position = vec4(position + (extrusion_vector * (rendered_thickness / 2.0) ), 0.0, 1.0); + + gl_Position = mvp * position; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/linearGradientFragmentShader.glsl b/vcl/opengl/shaders/linearGradientFragmentShader.glsl new file mode 100644 index 000000000..bd1137c16 --- /dev/null +++ b/vcl/opengl/shaders/linearGradientFragmentShader.glsl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 120 + +uniform vec4 start_color; +uniform vec4 end_color; +uniform mat3x3 transform; +varying vec2 tex_coord; + +void main(void) +{ + gl_FragColor = mix(end_color, start_color, + clamp(tex_coord.t, 0.0, 1.0)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/maskFragmentShader.glsl b/vcl/opengl/shaders/maskFragmentShader.glsl new file mode 100644 index 000000000..864869c89 --- /dev/null +++ b/vcl/opengl/shaders/maskFragmentShader.glsl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying vec2 tex_coord; +uniform sampler2D sampler; +uniform vec4 color; + +void main() { + vec4 texel0; + texel0 = texture2D(sampler, tex_coord); + gl_FragColor = color; + gl_FragColor.a = 1.0 - texel0.r; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/maskedTextureFragmentShader.glsl b/vcl/opengl/shaders/maskedTextureFragmentShader.glsl new file mode 100644 index 000000000..31c793897 --- /dev/null +++ b/vcl/opengl/shaders/maskedTextureFragmentShader.glsl @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +/*precision mediump float;*/ +varying vec2 tex_coord; +varying vec2 mask_coord; +uniform sampler2D sampler; +uniform sampler2D mask; + +void main() +{ + vec4 texel0, texel1; + texel0 = texture2D(sampler, tex_coord); + texel1 = texture2D(mask, mask_coord); + gl_FragColor = texel0; + gl_FragColor.a = 1.0 - texel1.r; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/maskedTextureVertexShader.glsl b/vcl/opengl/shaders/maskedTextureVertexShader.glsl new file mode 100644 index 000000000..6b5f327da --- /dev/null +++ b/vcl/opengl/shaders/maskedTextureVertexShader.glsl @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +attribute vec2 tex_coord_in; +attribute vec2 mask_coord_in; +varying vec2 tex_coord; +varying vec2 mask_coord; +uniform mat4 mvp; + +void main() +{ + gl_Position = mvp * position; + tex_coord = tex_coord_in; + mask_coord = mask_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/radialGradientFragmentShader.glsl b/vcl/opengl/shaders/radialGradientFragmentShader.glsl new file mode 100644 index 000000000..94a86eb95 --- /dev/null +++ b/vcl/opengl/shaders/radialGradientFragmentShader.glsl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 120 + +uniform vec4 start_color; +uniform vec4 end_color; +uniform vec2 center; +varying vec2 tex_coord; + +void main(void) +{ + gl_FragColor = mix(end_color, start_color, + clamp(distance(tex_coord, center), 0.0, 1.0)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/replaceColorFragmentShader.glsl b/vcl/opengl/shaders/replaceColorFragmentShader.glsl new file mode 100644 index 000000000..24f6008e2 --- /dev/null +++ b/vcl/opengl/shaders/replaceColorFragmentShader.glsl @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +varying vec2 tex_coord; +uniform sampler2D sampler; +uniform vec4 search_color; +uniform vec4 replace_color; +uniform float epsilon; + +void main() { + vec4 texel = texture2D(sampler, tex_coord); + vec4 diff = clamp(abs(texel - search_color) - epsilon, 0.0, 1.0); + float bump = max(0.0, 1.0 - ceil(diff.x + diff.y + diff.z)); + gl_FragColor = texel + bump * (replace_color - search_color); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/solidFragmentShader.glsl b/vcl/opengl/shaders/solidFragmentShader.glsl new file mode 100644 index 000000000..b77e2578d --- /dev/null +++ b/vcl/opengl/shaders/solidFragmentShader.glsl @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +/*precision mediump float;*/ + +uniform vec4 color; +void main() { + gl_FragColor = color; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/textureFragmentShader.glsl b/vcl/opengl/shaders/textureFragmentShader.glsl new file mode 100644 index 000000000..b1fedcba5 --- /dev/null +++ b/vcl/opengl/shaders/textureFragmentShader.glsl @@ -0,0 +1,20 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +/* precision mediump float; */ +varying vec2 tex_coord; +uniform sampler2D sampler; + +void main() { + gl_FragColor = texture2D(sampler, tex_coord); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/textureVertexShader.glsl b/vcl/opengl/shaders/textureVertexShader.glsl new file mode 100644 index 000000000..7fbdcf1eb --- /dev/null +++ b/vcl/opengl/shaders/textureVertexShader.glsl @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +attribute vec2 tex_coord_in; +varying vec2 tex_coord; +uniform mat4 mvp; + +void main() { + gl_Position = mvp * position; + tex_coord = tex_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/shaders/transformedTextureVertexShader.glsl b/vcl/opengl/shaders/transformedTextureVertexShader.glsl new file mode 100644 index 000000000..3d67f78e0 --- /dev/null +++ b/vcl/opengl/shaders/transformedTextureVertexShader.glsl @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#version 130 + +attribute vec4 position; +attribute vec2 tex_coord_in; +attribute vec2 mask_coord_in; +uniform vec2 viewport; +uniform mat4 transform; +uniform mat4 mvp; +varying vec2 tex_coord; +varying vec2 mask_coord; + +void main() { + vec4 pos = mvp * transform * position; + gl_Position = pos; + tex_coord = tex_coord_in; + mask_coord = mask_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx new file mode 100644 index 000000000..9f4acc0fc --- /dev/null +++ b/vcl/opengl/texture.cxx @@ -0,0 +1,606 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +namespace +{ + +constexpr GLenum constInternalFormat = GL_RGBA8; + +} // end anonymous namespace + +// texture with allocated size +ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, bool bAllocate ) : + mnTexture( 0 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ), + mnOptStencil( 0 ) +{ + OpenGLVCLContextZone aContextZone; + + auto& rState = OpenGLContext::getVCLContext()->state(); + TextureState::generate(mnTexture); + rState.texture().active(0); + rState.texture().bind(mnTexture); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + if( bAllocate ) + { +#ifdef DBG_UTIL + std::vector< sal_uInt8 > buffer; + buffer.resize( nWidth * nHeight * 4 ); + for( int i = 0; i < nWidth * nHeight; ++i ) + { // pre-fill the texture with deterministic garbage + bool odd = (i & 0x01); + buffer[ i * 4 ] = odd ? 0x40 : 0xBF; + buffer[ i * 4 + 1 ] = 0x80; + buffer[ i * 4 + 2 ] = odd ? 0xBF : 0x40; + buffer[ i * 4 + 3 ] = 0xFF; + } + glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); +#else + glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr ); +#endif + CHECK_GL_ERROR(); + } + + VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " allocate" ); +} + +// texture with content retrieved from FBO +ImplOpenGLTexture::ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ) : + mnTexture( 0 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ), + mnOptStencil( 0 ) +{ + OpenGLVCLContextZone aContextZone; + + // FIXME We need the window height here + // nY = GetHeight() - nHeight - nY; + + auto& rState = OpenGLContext::getVCLContext()->state(); + TextureState::generate(mnTexture); + rState.texture().active(0); + rState.texture().bind(mnTexture); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + glCopyTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, nX, nY, nWidth, nHeight, 0 ); + CHECK_GL_ERROR(); + + VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from x" << nX << ", y" << nY ); +} + +// texture from buffer data +ImplOpenGLTexture::ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ) : + mnTexture( 0 ), + mnWidth( nWidth ), + mnHeight( nHeight ), + mnFilter( GL_NEAREST ), + mnOptStencil( 0 ) +{ + OpenGLVCLContextZone aContextZone; + + auto& rState = OpenGLContext::getVCLContext()->state(); + TextureState::generate(mnTexture); + rState.texture().active(0); + rState.texture().bind(mnTexture); + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + CHECK_GL_ERROR(); + glTexImage2D( GL_TEXTURE_2D, 0, constInternalFormat, mnWidth, mnHeight, 0, nFormat, nType, pData ); + CHECK_GL_ERROR(); + + VCL_GL_INFO( "OpenGLTexture " << mnTexture << " " << nWidth << "x" << nHeight << " from data" ); +} + +GLuint ImplOpenGLTexture::AddStencil() +{ + assert( mnOptStencil == 0 ); + + glGenRenderbuffers( 1, &mnOptStencil ); + CHECK_GL_ERROR(); + glBindRenderbuffer( GL_RENDERBUFFER, mnOptStencil ); + CHECK_GL_ERROR(); + VCL_GL_INFO( "Allocate stencil " << mnWidth << " x " << mnHeight ); + glRenderbufferStorage( GL_RENDERBUFFER, GL_STENCIL_INDEX, + mnWidth, mnHeight ); + CHECK_GL_ERROR(); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + CHECK_GL_ERROR(); + + return mnOptStencil; +} + +ImplOpenGLTexture::~ImplOpenGLTexture() +{ + VCL_GL_INFO( "~OpenGLTexture " << mnTexture ); + if( mnTexture != 0 ) + { + // During shutdown GL is already de-initialized, so we should not try to create a new context. + OpenGLZone aZone; + rtl::Reference xContext = OpenGLContext::getVCLContext(false); + if( xContext.is() ) + { + // FIXME: this is really not optimal performance-wise. + + // Check we have been correctly un-bound from all framebuffers. + ImplSVData* pSVData = ImplGetSVData(); + rtl::Reference pContext = pSVData->maGDIData.mpLastContext; + + if( pContext.is() ) + { + pContext->makeCurrent(); + pContext->UnbindTextureFromFramebuffers( mnTexture ); + } + + if( mnOptStencil != 0 ) + { + glDeleteRenderbuffers( 1, &mnOptStencil ); + mnOptStencil = 0; + } + auto& rState = pContext->state(); + rState.texture().unbindAndDelete(mnTexture); + mnTexture = 0; + } + else + { + mnOptStencil = 0; + mnTexture = 0; + } + } +} + +bool ImplOpenGLTexture::InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData) +{ + if (!pData || mnTexture == 0) + return false; + + rtl::Reference xContext = OpenGLContext::getVCLContext(); + xContext->state().texture().active(0); + xContext->state().texture().bind(mnTexture); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + CHECK_GL_ERROR(); + glTexSubImage2D(GL_TEXTURE_2D, 0, nX, mnHeight - nY - nHeight, nWidth, nHeight, nFormat, nType, pData); + CHECK_GL_ERROR(); + + VCL_GL_INFO( "OpenGLTexture " << mnTexture << " Insert buff. to " << nX << " " << nY + << " size " << nWidth << "x" << nHeight << " from data" ); + + return true; +} + +void ImplOpenGLTexture::InitializeSlotMechanism(int nInitialSlotSize) +{ + if (mpSlotReferences) + return; + + mpSlotReferences.reset(new std::vector(nInitialSlotSize, 0)); +} + +void ImplOpenGLTexture::IncreaseRefCount(int nSlotNumber) +{ + if (mpSlotReferences && nSlotNumber >= 0) + { + if (nSlotNumber >= int(mpSlotReferences->size())) + mpSlotReferences->resize(nSlotNumber + 1, 0); + + mpSlotReferences->at(nSlotNumber)++; + } +} + +void ImplOpenGLTexture::DecreaseRefCount(int nSlotNumber) +{ + if (mpSlotReferences && nSlotNumber >= 0) + { + if (nSlotNumber >= int(mpSlotReferences->size())) + mpSlotReferences->resize(nSlotNumber, 0); + + mpSlotReferences->at(nSlotNumber)--; + + if (mpSlotReferences->at(nSlotNumber) == 0 && mFunctSlotDeallocateCallback) + { + mFunctSlotDeallocateCallback(nSlotNumber); + } + } +} + +OpenGLTexture::OpenGLTexture() : + maRect( 0, 0, 0, 0 ), + mpImpl(), + mnSlotNumber(-1) +{ +} + +OpenGLTexture::OpenGLTexture(const std::shared_ptr& rpImpl, tools::Rectangle aRectangle, int nSlotNumber) + : maRect(aRectangle) + , mpImpl(rpImpl) + , mnSlotNumber(nSlotNumber) +{ + if (mpImpl) + mpImpl->IncreaseRefCount(nSlotNumber); +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, bool bAllocate ) + : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) + , mpImpl(std::make_shared(nWidth, nHeight, bAllocate)) + , mnSlotNumber(-1) +{ +} + +OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) + : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) + , mpImpl(std::make_shared(nX, nY, nWidth, nHeight)) + , mnSlotNumber(-1) +{ +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ) + : maRect( Point( 0, 0 ), Size( nWidth, nHeight ) ) + , mpImpl(std::make_shared(nWidth, nHeight, nFormat, nType, pData)) + , mnSlotNumber(-1) +{ + +} + +OpenGLTexture::OpenGLTexture(const OpenGLTexture& rTexture) + : maRect(rTexture.maRect) + , mpImpl(rTexture.mpImpl) + , mnSlotNumber(rTexture.mnSlotNumber) +{ + if (mpImpl) + mpImpl->IncreaseRefCount(mnSlotNumber); +} + +OpenGLTexture::OpenGLTexture(OpenGLTexture&& rTexture) noexcept + : maRect(rTexture.maRect) + , mpImpl(std::move(rTexture.mpImpl)) + , mnSlotNumber(rTexture.mnSlotNumber) +{ +} + +OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture, + int nX, int nY, int nWidth, int nHeight ) +{ + maRect = tools::Rectangle( Point( rTexture.maRect.Left() + nX, rTexture.maRect.Top() + nY ), + Size( nWidth, nHeight ) ); + mpImpl = rTexture.mpImpl; + mnSlotNumber = rTexture.mnSlotNumber; + if (mpImpl) + mpImpl->IncreaseRefCount(mnSlotNumber); + VCL_GL_INFO( "Copying texture " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); +} + +OpenGLTexture::~OpenGLTexture() +{ + if (mpImpl) + mpImpl->DecreaseRefCount(mnSlotNumber); +} + +bool OpenGLTexture::IsUnique() const +{ + return !mpImpl || (mpImpl.use_count() == 1); +} + +GLuint OpenGLTexture::Id() const +{ + if (mpImpl) + return mpImpl->mnTexture; + return 0; +} + +int OpenGLTexture::GetWidth() const +{ + return maRect.GetWidth(); +} + +int OpenGLTexture::GetHeight() const +{ + return maRect.GetHeight(); +} + +GLuint OpenGLTexture::StencilId() const +{ + return mpImpl ? mpImpl->mnOptStencil : 0; +} + +GLuint OpenGLTexture::AddStencil() +{ + if (mpImpl) + return mpImpl->AddStencil(); + else + return 0; +} + +void OpenGLTexture::GetCoord( GLfloat* pCoord, const SalTwoRect& rPosAry, bool bInverted ) const +{ + VCL_GL_INFO( "Getting coord " << Id() << " [" << maRect.Left() << "," << maRect.Top() << "] " << GetWidth() << "x" << GetHeight() ); + + if (!IsValid()) + { + pCoord[0] = pCoord[1] = pCoord[2] = pCoord[3] = 0.0f; + pCoord[4] = pCoord[5] = pCoord[6] = pCoord[7] = 0.0f; + return; + } + + pCoord[0] = pCoord[2] = (maRect.Left() + rPosAry.mnSrcX) / static_cast(mpImpl->mnWidth); + pCoord[4] = pCoord[6] = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / static_cast(mpImpl->mnWidth); + + if( !bInverted ) + { + pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast(mpImpl->mnHeight); + pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast(mpImpl->mnHeight); + } + else + { + pCoord[1] = pCoord[7] = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / static_cast(mpImpl->mnHeight); + pCoord[3] = pCoord[5] = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / static_cast(mpImpl->mnHeight); + } +} + +void OpenGLTexture::GetTextureRect(const SalTwoRect& rPosAry, GLfloat& x1, GLfloat& x2, GLfloat& y1, GLfloat& y2) const +{ + if (IsValid()) + { + double fTextureWidth(mpImpl->mnWidth); + double fTextureHeight(mpImpl->mnHeight); + + x1 = (maRect.Left() + rPosAry.mnSrcX) / fTextureWidth; + x2 = (maRect.Left() + rPosAry.mnSrcX + rPosAry.mnSrcWidth) / fTextureWidth; + + y1 = 1.0f - (maRect.Top() + rPosAry.mnSrcY) / fTextureHeight; + y2 = 1.0f - (maRect.Top() + rPosAry.mnSrcY + rPosAry.mnSrcHeight) / fTextureHeight; + } +} + +template <> +void OpenGLTexture::FillCoords(std::vector& rCoords, const SalTwoRect& rPosAry) const +{ + GLfloat x1 = 0.0f; + GLfloat x2 = 0.0f; + GLfloat y1 = 0.0f; + GLfloat y2 = 0.0f; + + GetTextureRect(rPosAry, x1, x2, y1, y2); + + rCoords.insert(rCoords.end(), { + x1, y2, x1, y1, + x2, y1, x2, y2 + }); +} + +template <> +void OpenGLTexture::FillCoords(std::vector& rCoords, const SalTwoRect& rPosAry) const +{ + GLfloat x1 = 0.0f; + GLfloat x2 = 0.0f; + GLfloat y1 = 0.0f; + GLfloat y2 = 0.0f; + + GetTextureRect(rPosAry, x1, x2, y1, y2); + + rCoords.insert(rCoords.end(), { + x1, y1, x2, y1, x1, y2, + x1, y2, x2, y1, x2, y2 + }); +} + +void OpenGLTexture::GetWholeCoord( GLfloat* pCoord ) const +{ + if( GetWidth() != mpImpl->mnWidth || GetHeight() != mpImpl->mnHeight ) + { + pCoord[0] = pCoord[2] = maRect.Left() / static_cast(mpImpl->mnWidth); + pCoord[4] = pCoord[6] = maRect.Right() / static_cast(mpImpl->mnWidth); + pCoord[3] = pCoord[5] = 1.0f - maRect.Top() / static_cast(mpImpl->mnHeight); + pCoord[1] = pCoord[7] = 1.0f - maRect.Bottom() / static_cast(mpImpl->mnHeight); + } + else + { + pCoord[0] = pCoord[2] = 0; + pCoord[4] = pCoord[6] = 1; + pCoord[1] = pCoord[7] = 0; + pCoord[3] = pCoord[5] = 1; + } +} + +GLenum OpenGLTexture::GetFilter() const +{ + if( mpImpl ) + return mpImpl->mnFilter; + return GL_NEAREST; +} + +bool OpenGLTexture::CopyData(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8 const * pData) +{ + if (!pData || !IsValid()) + return false; + + int nX = maRect.Left(); + int nY = maRect.Top(); + + return mpImpl->InsertBuffer(nX, nY, nWidth, nHeight, nFormat, nType, pData); +} + +void OpenGLTexture::SetFilter( GLenum nFilter ) +{ + if( mpImpl ) + { + mpImpl->mnFilter = nFilter; + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter ); + CHECK_GL_ERROR(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter ); + CHECK_GL_ERROR(); + } +} + +void OpenGLTexture::Bind() +{ + if (IsValid()) + { + OpenGLContext::getVCLContext()->state().texture().bind(mpImpl->mnTexture); + } + else + VCL_GL_INFO( "OpenGLTexture::Binding invalid texture" ); + + CHECK_GL_ERROR(); +} + +void OpenGLTexture::Unbind() +{ + if (IsValid()) + { + OpenGLContext::getVCLContext()->state().texture().unbind(mpImpl->mnTexture); + } +} + +void OpenGLTexture::SaveToFile(const OUString& rFileName) +{ + std::vector aBuffer(GetWidth() * GetHeight() * 4); + Read(OpenGLHelper::OptimalBufferFormat(), GL_UNSIGNED_BYTE, aBuffer.data()); + BitmapEx aBitmap = OpenGLHelper::ConvertBufferToBitmapEx(aBuffer.data(), GetWidth(), GetHeight()); + try + { + vcl::PNGWriter aWriter(aBitmap); + SvFileStream sOutput(rFileName, StreamMode::WRITE); + aWriter.Write(sOutput); + sOutput.Close(); + } + catch (...) + { + SAL_WARN("vcl.opengl", "Error writing png to " << rFileName); + } +} + +void OpenGLTexture::Read( GLenum nFormat, GLenum nType, sal_uInt8* pData ) +{ + if (!IsValid()) + { + SAL_WARN( "vcl.opengl", "Can't read invalid texture" ); + return; + } + + OpenGLVCLContextZone aContextZone; + + VCL_GL_INFO( "Reading texture " << Id() << " " << GetWidth() << "x" << GetHeight() ); + + if( GetWidth() == mpImpl->mnWidth && GetHeight() == mpImpl->mnHeight ) + { + Bind(); + glPixelStorei( GL_PACK_ALIGNMENT, 1 ); + CHECK_GL_ERROR(); + // XXX: Call not available with GLES 2.0 + glGetTexImage( GL_TEXTURE_2D, 0, nFormat, nType, pData ); + CHECK_GL_ERROR(); + Unbind(); + } + else + { + long nWidth = maRect.GetWidth(); + long nHeight = maRect.GetHeight(); + long nX = maRect.Left(); + long nY = mpImpl->mnHeight - maRect.Top() - nHeight; + + // Retrieve current context + ImplSVData* pSVData = ImplGetSVData(); + rtl::Reference pContext = pSVData->maGDIData.mpLastContext; + OpenGLFramebuffer* pFramebuffer = pContext->AcquireFramebuffer(*this); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + CHECK_GL_ERROR(); + glReadPixels(nX, nY, nWidth, nHeight, nFormat, nType, pData); + CHECK_GL_ERROR(); + OpenGLContext::ReleaseFramebuffer(pFramebuffer); + } +} + +OpenGLTexture::operator bool() const +{ + return IsValid(); +} + +OpenGLTexture& OpenGLTexture::operator=(const OpenGLTexture& rTexture) +{ + OpenGLTexture aTemp(rTexture); + *this = std::move(aTemp); + return *this; +} + +OpenGLTexture& OpenGLTexture::operator=(OpenGLTexture&& rTexture) +{ + if (mpImpl) + mpImpl->DecreaseRefCount(mnSlotNumber); + + maRect = rTexture.maRect; + mpImpl = std::move(rTexture.mpImpl); + mnSlotNumber = rTexture.mnSlotNumber; + + return *this; +} + +bool OpenGLTexture::operator==( const OpenGLTexture& rTexture ) const +{ + return (mpImpl == rTexture.mpImpl + && maRect == rTexture.maRect + && mnSlotNumber == rTexture.mnSlotNumber); +} + +bool OpenGLTexture::operator!=( const OpenGLTexture& rTexture ) const +{ + return !( *this == rTexture ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/WinDeviceInfo.cxx b/vcl/opengl/win/WinDeviceInfo.cxx new file mode 100644 index 000000000..301c8e74d --- /dev/null +++ b/vcl/opengl/win/WinDeviceInfo.cxx @@ -0,0 +1,494 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace { + +bool GetKeyValue(const WCHAR* keyLocation, const WCHAR* keyName, OUString& destString, int type) +{ + HKEY key; + DWORD dwcbData; + DWORD dValue; + DWORD resultType; + LONG result; + bool retval = true; + + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyLocation, 0, KEY_QUERY_VALUE, &key); + if (result != ERROR_SUCCESS) + { + return false; + } + + switch (type) + { + case REG_DWORD: + { + // We only use this for vram size + dwcbData = sizeof(dValue); + result = RegQueryValueExW(key, keyName, nullptr, &resultType, + reinterpret_cast(&dValue), &dwcbData); + if (result == ERROR_SUCCESS && resultType == REG_DWORD) + { + dValue = dValue / 1024 / 1024; + destString += OUString::number(int32_t(dValue)); + } + else + { + retval = false; + } + break; + } + case REG_MULTI_SZ: + { + // A chain of null-separated strings; we convert the nulls to spaces + WCHAR wCharValue[1024]; + dwcbData = sizeof(wCharValue); + + result = RegQueryValueExW(key, keyName, nullptr, &resultType, + reinterpret_cast(wCharValue), &dwcbData); + if (result == ERROR_SUCCESS && resultType == REG_MULTI_SZ) + { + // This bit here could probably be cleaner. + bool isValid = false; + + DWORD strLen = dwcbData/sizeof(wCharValue[0]); + for (DWORD i = 0; i < strLen; i++) + { + if (wCharValue[i] == '\0') + { + if (i < strLen - 1 && wCharValue[i + 1] == '\0') + { + isValid = true; + break; + } + else + { + wCharValue[i] = ' '; + } + } + } + + // ensure wCharValue is null terminated + wCharValue[strLen-1] = '\0'; + + if (isValid) + destString = OUString(o3tl::toU(wCharValue)); + + } + else + { + retval = false; + } + + break; + } + } + RegCloseKey(key); + + return retval; +} + +// The device ID is a string like PCI\VEN_15AD&DEV_0405&SUBSYS_040515AD +// this function is used to extract the id's out of it +uint32_t ParseIDFromDeviceID(const OUString &key, const char *prefix, int length) +{ + OUString id = key.toAsciiUpperCase(); + OUString aPrefix = OUString::fromUtf8(prefix); + int32_t start = id.indexOf(aPrefix); + if (start != -1) + { + id = id.copy(start + aPrefix.getLength(), length); + } + return id.toUInt32(16); +} + +/* Other interesting places for info: + * IDXGIAdapter::GetDesc() + * IDirectDraw7::GetAvailableVidMem() + * e->GetAvailableTextureMem() + * */ + +template void appendIntegerWithPadding(OUString& rString, T value, sal_uInt32 nChars) +{ + rString += "0x"; + OUString aValue = OUString::number(value, 16); + sal_Int32 nLength = aValue.getLength(); + sal_uInt32 nPadLength = nChars - nLength; + assert(nPadLength >= 0); + OUStringBuffer aBuffer; + for (sal_uInt32 i = 0; i < nPadLength; ++i) + { + aBuffer.append("0"); + } + rString += aBuffer.makeStringAndClear() + aValue; +} + +#define DEVICE_KEY_PREFIX L"\\Registry\\Machine\\" +} + +WinOpenGLDeviceInfo::WinOpenGLDeviceInfo(): + mbHasDualGPU(false), + mbRDP(false) +{ + GetData(); +} + +WinOpenGLDeviceInfo::~WinOpenGLDeviceInfo() +{ +} + +static OUString getBlacklistFile() +{ + OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER); + rtl::Bootstrap::expandMacros(url); + + return url + "/opengl/opengl_blacklist_windows.xml"; +} + +bool WinOpenGLDeviceInfo::FindBlocklistedDeviceInList() +{ + return DriverBlocklist::IsDeviceBlocked( getBlacklistFile(), DriverBlocklist::VersionType::OpenGL, + maDriverVersion, maAdapterVendorID, maAdapterDeviceID); +} + +namespace { + +OUString getCacheFolder() +{ + OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); + rtl::Bootstrap::expandMacros(url); + + osl::Directory::create(url); + + return url; +} + +void writeToLog(SvStream& rStrm, const char* pKey, const OUString & rVal) +{ + rStrm.WriteCharPtr(pKey); + rStrm.WriteCharPtr(": "); + rStrm.WriteOString(OUStringToOString(rVal, RTL_TEXTENCODING_UTF8)); + rStrm.WriteChar('\n'); +} + +} + +bool WinOpenGLDeviceInfo::isDeviceBlocked() +{ + CrashReporter::addKeyValue("OpenGLVendor", maAdapterVendorID, CrashReporter::AddItem); + CrashReporter::addKeyValue("OpenGLDevice", maAdapterDeviceID, CrashReporter::AddItem); + CrashReporter::addKeyValue("OpenGLDriver", maDriverVersion, CrashReporter::Write); + + SAL_INFO("vcl.opengl", maDriverVersion); + SAL_INFO("vcl.opengl", maDriverDate); + SAL_INFO("vcl.opengl", maDeviceID); + SAL_INFO("vcl.opengl", maAdapterVendorID); + SAL_INFO("vcl.opengl", maAdapterDeviceID); + SAL_INFO("vcl.opengl", maAdapterSubsysID); + SAL_INFO("vcl.opengl", maDeviceKey); + SAL_INFO("vcl.opengl", maDeviceString); + + OUString aCacheFolder = getCacheFolder(); + + OUString aCacheFile(aCacheFolder + "/opengl_device.log"); + SvFileStream aOpenGLLogFile(aCacheFile, StreamMode::WRITE|StreamMode::TRUNC); + + writeToLog(aOpenGLLogFile, "DriverVersion", maDriverVersion); + writeToLog(aOpenGLLogFile, "DriverDate", maDriverDate); + writeToLog(aOpenGLLogFile, "DeviceID", maDeviceID); + writeToLog(aOpenGLLogFile, "AdapterVendorID", maAdapterVendorID); + writeToLog(aOpenGLLogFile, "AdapterDeviceID", maAdapterDeviceID); + writeToLog(aOpenGLLogFile, "AdapterSubsysID", maAdapterSubsysID); + writeToLog(aOpenGLLogFile, "DeviceKey", maDeviceKey); + writeToLog(aOpenGLLogFile, "DeviceString", maDeviceString); + + // Check if the device is blocked from the downloaded blocklist. If not, check + // the static list after that. This order is used so that we can later escape + // out of static blocks (i.e. if we were wrong or something was patched, we + // can back out our static block without doing a release). + if (mbRDP) + { + SAL_WARN("vcl.opengl", "all OpenGL blocked for RDP sessions"); + return true; + } + + return FindBlocklistedDeviceInList(); +} + +void WinOpenGLDeviceInfo::GetData() +{ + DISPLAY_DEVICEW displayDevice; + displayDevice.cb = sizeof(displayDevice); + + int deviceIndex = 0; + + while (EnumDisplayDevicesW(nullptr, deviceIndex, &displayDevice, 0)) + { + if (displayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) + { + break; + } + deviceIndex++; + } + + // make sure the string is null terminated + // (using the term "null" here to mean a zero UTF-16 unit) + if (wcsnlen(displayDevice.DeviceKey, SAL_N_ELEMENTS(displayDevice.DeviceKey)) + == SAL_N_ELEMENTS(displayDevice.DeviceKey)) + { + // we did not find a null + SAL_WARN("vcl.opengl", "string not null terminated"); + return; + } + + /* DeviceKey is "reserved" according to MSDN so we'll be careful with it */ + /* check that DeviceKey begins with DEVICE_KEY_PREFIX */ + /* some systems have a DeviceKey starting with \REGISTRY\Machine\ so we need to compare case insensitively */ + if (_wcsnicmp(displayDevice.DeviceKey, DEVICE_KEY_PREFIX, SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1) != 0) + { + SAL_WARN("vcl.opengl", "incorrect DeviceKey"); + return; + } + + // chop off DEVICE_KEY_PREFIX + maDeviceKey = o3tl::toU(displayDevice.DeviceKey) + SAL_N_ELEMENTS(DEVICE_KEY_PREFIX)-1; + + maDeviceID = o3tl::toU(displayDevice.DeviceID); + maDeviceString = o3tl::toU(displayDevice.DeviceString); + + if (maDeviceID.isEmpty() && + (maDeviceString == "RDPDD Chained DD" || + (maDeviceString == "RDPUDD Chained DD"))) + { + // we need to block RDP as it does not provide OpenGL 2.1+ + mbRDP = true; + SAL_WARN("vcl.opengl", "RDP => blocked"); + return; + } + + /* create a device information set composed of the current display device */ + HDEVINFO devinfo = SetupDiGetClassDevsW(nullptr, o3tl::toW(maDeviceID.getStr()), nullptr, + DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES); + + if (devinfo != INVALID_HANDLE_VALUE) + { + HKEY key; + LONG result; + WCHAR value[255]; + DWORD dwcbData; + SP_DEVINFO_DATA devinfoData; + DWORD memberIndex = 0; + + devinfoData.cbSize = sizeof(devinfoData); + /* enumerate device information elements in the device information set */ + while (SetupDiEnumDeviceInfo(devinfo, memberIndex++, &devinfoData)) + { + /* get a string that identifies the device's driver key */ + if (SetupDiGetDeviceRegistryPropertyW(devinfo, + &devinfoData, + SPDRP_DRIVER, + nullptr, + reinterpret_cast(value), + sizeof(value), + nullptr)) + { + OUString driverKey(OUStringLiteral("System\\CurrentControlSet\\Control\\Class\\") + o3tl::toU(value)); + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, o3tl::toW(driverKey.getStr()), 0, KEY_QUERY_VALUE, &key); + if (result == ERROR_SUCCESS) + { + /* we've found the driver we're looking for */ + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverVersion", nullptr, nullptr, + reinterpret_cast(value), &dwcbData); + if (result == ERROR_SUCCESS) + { + maDriverVersion = OUString(o3tl::toU(value)); + } + else + { + // If the entry wasn't found, assume the worst (0.0.0.0). + maDriverVersion = OUString("0.0.0.0"); + } + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr, + reinterpret_cast(value), &dwcbData); + if (result == ERROR_SUCCESS) + { + maDriverDate = o3tl::toU(value); + } + else + { + // Again, assume the worst + maDriverDate = OUString("01-01-1970"); + } + RegCloseKey(key); + break; + } + } + } + + SetupDiDestroyDeviceInfoList(devinfo); + } + else + { + SAL_WARN("vcl.opengl", "invalid handle value"); + } + + appendIntegerWithPadding(maAdapterVendorID, ParseIDFromDeviceID(maDeviceID, "VEN_", 4), 4); + appendIntegerWithPadding(maAdapterDeviceID, ParseIDFromDeviceID(maDeviceID, "&DEV_", 4), 4); + appendIntegerWithPadding(maAdapterSubsysID, ParseIDFromDeviceID(maDeviceID, "&SUBSYS_", 8), 8); + + // We now check for second display adapter. + + // Device interface class for display adapters. + CLSID GUID_DISPLAY_DEVICE_ARRIVAL; + HRESULT hresult = CLSIDFromString(L"{1CA05180-A699-450A-9A0C-DE4FBE3DDD89}", + &GUID_DISPLAY_DEVICE_ARRIVAL); + if (hresult == NOERROR) + { + devinfo = SetupDiGetClassDevsW(&GUID_DISPLAY_DEVICE_ARRIVAL, + nullptr, nullptr, + DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); + + if (devinfo != INVALID_HANDLE_VALUE) + { + HKEY key; + LONG result; + WCHAR value[255]; + DWORD dwcbData; + SP_DEVINFO_DATA devinfoData; + DWORD memberIndex = 0; + devinfoData.cbSize = sizeof(devinfoData); + + OUString aAdapterDriver2; + OUString aDeviceID2; + OUString aDriverVersion2; + OUString aDriverDate2; + uint32_t adapterVendorID2; + uint32_t adapterDeviceID2; + + /* enumerate device information elements in the device information set */ + while (SetupDiEnumDeviceInfo(devinfo, memberIndex++, &devinfoData)) + { + /* get a string that identifies the device's driver key */ + if (SetupDiGetDeviceRegistryPropertyW(devinfo, + &devinfoData, + SPDRP_DRIVER, + nullptr, + reinterpret_cast(value), + sizeof(value), + nullptr)) + { + OUString driverKey2(OUStringLiteral("System\\CurrentControlSet\\Control\\Class\\") + o3tl::toU(value)); + result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, o3tl::toW(driverKey2.getStr()), 0, KEY_QUERY_VALUE, &key); + if (result == ERROR_SUCCESS) + { + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"MatchingDeviceId", nullptr, + nullptr, reinterpret_cast(value), &dwcbData); + if (result != ERROR_SUCCESS) + { + continue; + } + aDeviceID2 = o3tl::toU(value); + OUString aAdapterVendorID2String; + OUString aAdapterDeviceID2String; + adapterVendorID2 = ParseIDFromDeviceID(aDeviceID2, "VEN_", 4); + appendIntegerWithPadding(aAdapterVendorID2String, adapterVendorID2, 4); + adapterDeviceID2 = ParseIDFromDeviceID(aDeviceID2, "&DEV_", 4); + appendIntegerWithPadding(aAdapterDeviceID2String, adapterDeviceID2, 4); + if (maAdapterVendorID == aAdapterVendorID2String && + maAdapterDeviceID == aAdapterDeviceID2String) + { + RegCloseKey(key); + continue; + } + + // If this device is missing driver information, it is unlikely to + // be a real display adapter. + if (!GetKeyValue(o3tl::toW(driverKey2.getStr()), L"InstalledDisplayDrivers", + aAdapterDriver2, REG_MULTI_SZ)) + { + RegCloseKey(key); + continue; + } + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverVersion", nullptr, nullptr, + reinterpret_cast(value), &dwcbData); + if (result != ERROR_SUCCESS) + { + RegCloseKey(key); + continue; + } + aDriverVersion2 = o3tl::toU(value); + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverDate", nullptr, nullptr, + reinterpret_cast(value), &dwcbData); + if (result != ERROR_SUCCESS) + { + RegCloseKey(key); + continue; + } + aDriverDate2 = o3tl::toU(value); + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"Device Description", nullptr, + nullptr, reinterpret_cast(value), &dwcbData); + if (result != ERROR_SUCCESS) + { + dwcbData = sizeof(value); + result = RegQueryValueExW(key, L"DriverDesc", nullptr, nullptr, + reinterpret_cast(value), &dwcbData); + } + RegCloseKey(key); + if (result == ERROR_SUCCESS) + { + mbHasDualGPU = true; + maDeviceString2 = o3tl::toU(value); + maDeviceID2 = aDeviceID2; + maDeviceKey2 = driverKey2; + maDriverVersion2 = aDriverVersion2; + maDriverDate2 = aDriverDate2; + appendIntegerWithPadding(maAdapterVendorID2, adapterVendorID2, 4); + appendIntegerWithPadding(maAdapterDeviceID2, adapterDeviceID2, 4); + appendIntegerWithPadding(maAdapterSubsysID2, ParseIDFromDeviceID(maDeviceID2, "&SUBSYS_", 8), 8); + break; + } + } + } + } + + SetupDiDestroyDeviceInfoList(devinfo); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx new file mode 100644 index 000000000..eabfe8a09 --- /dev/null +++ b/vcl/opengl/win/gdiimpl.cxx @@ -0,0 +1,898 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static std::vector g_vShareList; +static bool g_bAnyCurrent; + +namespace { + +class GLWinWindow : public GLWindow +{ +public: + HWND hWnd; + HDC hDC; + HGLRC hRC; + GLWinWindow(); +}; + +} + +GLWinWindow::GLWinWindow() + : hWnd(nullptr) + , hDC(nullptr) + , hRC(nullptr) +{ +} + +namespace { + +class WinOpenGLContext : public OpenGLContext +{ +public: + bool init( HDC hDC, HWND hWnd ); + virtual void initWindow() override; +private: + GLWinWindow m_aGLWin; + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } + virtual bool ImplInit() override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +} + +void WinOpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + SwapBuffers(m_aGLWin.hDC); + + BuffersSwapped(); +} + +void WinOpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; +} + +static void ensureDispatchTable() +{ + thread_local bool bEpoxyDispatchMakeCurrentCalled = false; + if (!bEpoxyDispatchMakeCurrentCalled) + { + epoxy_handle_external_wglMakeCurrent(); + bEpoxyDispatchMakeCurrentCalled = true; + } +} + +bool WinOpenGLContext::isCurrent() +{ + OpenGLZone aZone; + if (!g_bAnyCurrent || !m_aGLWin.hRC) + return false; + ensureDispatchTable(); + return wglGetCurrentContext() == m_aGLWin.hRC && wglGetCurrentDC() == m_aGLWin.hDC; +} + +bool WinOpenGLContext::isAnyCurrent() +{ + return g_bAnyCurrent && wglGetCurrentContext() != nullptr; +} + +void WinOpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + + ensureDispatchTable(); + + if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) + { + g_bAnyCurrent = false; + DWORD nLastError = GetLastError(); + if (nLastError != ERROR_SUCCESS) + SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(nLastError)); + return; + } + + g_bAnyCurrent = true; + + registerAsCurrent(); +} + +bool WinOpenGLContext::init(HDC hDC, HWND hWnd) +{ + if (isInitialized()) + return true; + + m_aGLWin.hDC = hDC; + m_aGLWin.hWnd = hWnd; + return ImplInit(); +} + +void WinOpenGLContext::initWindow() +{ + if( !m_pChildWindow ) + { + SystemWindowData winData = generateWinData(mpWindow, false); + m_pChildWindow = VclPtr::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + const SystemEnvData* sysData(m_pChildWindow->GetSystemData()); + m_aGLWin.hWnd = sysData->hWnd; + } + + m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); +} + +void WinOpenGLContext::destroyCurrentContext() +{ + if (m_aGLWin.hRC) + { + std::vector::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC); + if (itr != g_vShareList.end()) + g_vShareList.erase(itr); + + if (wglGetCurrentContext() != nullptr) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + } + wglDeleteContext( m_aGLWin.hRC ); + ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC ); + m_aGLWin.hRC = nullptr; + } +} + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_CREATE: + return 0; + case WM_CLOSE: + PostQuitMessage(0); + return 0; + case WM_DESTROY: + return 0; + default: + return DefWindowProcW(hwnd, message, wParam, lParam); + } +} + +static bool InitTempWindow(HWND& hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWinWindow& glWin) +{ + OpenGLZone aZone; + + PIXELFORMATDESCRIPTOR pfd = inPfd; + int ret; + WNDCLASSW wc; + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = wc.cbWndExtra = 0; + wc.hInstance = nullptr; + wc.hIcon = nullptr; + wc.hCursor = nullptr; + wc.hbrBackground = nullptr; + wc.lpszMenuName = nullptr; + wc.lpszClassName = L"GLRenderer"; + RegisterClassW(&wc); + hwnd = CreateWindowW(wc.lpszClassName, nullptr, WS_DISABLED, 0, 0, width, height, nullptr, nullptr, wc.hInstance, nullptr); + glWin.hDC = GetDC(hwnd); + + int nPixelFormat = ChoosePixelFormat(glWin.hDC, &pfd); + if (!nPixelFormat) + { + ReleaseDC(hwnd, glWin.hDC); + DestroyWindow(hwnd); + return false; + } + ret = SetPixelFormat(glWin.hDC, nPixelFormat, &pfd); + if(!ret) + { + ReleaseDC(hwnd, glWin.hDC); + DestroyWindow(hwnd); + return false; + } + glWin.hRC = wglCreateContext(glWin.hDC); + if(!(glWin.hRC)) + { + ReleaseDC(hwnd, glWin.hDC); + DestroyWindow(hwnd); + return false; + } + ret = wglMakeCurrent(glWin.hDC, glWin.hRC); + if(!ret) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hwnd, glWin.hDC); + DestroyWindow(hwnd); + return false; + } + g_bAnyCurrent = false; + + return true; +} + +static bool WGLisExtensionSupported(const char *extension) +{ + OpenGLZone aZone; + + const size_t extlen = strlen(extension); + const char *supported = nullptr; + + // Try to use wglGetExtensionStringARB on current DC, if possible + PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB"); + + if (wglGetExtString) + supported = reinterpret_cast(wglGetExtString)(wglGetCurrentDC()); + // If that failed, try standard OpenGL extensions string + if (supported == nullptr) + supported = reinterpret_cast(glGetString(GL_EXTENSIONS)); + // If that failed too, must be no extensions supported + if (supported == nullptr) + return false; + + // Begin examination at start of string, increment by 1 on false match + for (const char* p = supported; ; p++) + { + // Advance p up to the next possible match + p = strstr(p, extension); + + if (p == nullptr) + return false; // No Match + + // Make sure that match is at the start of the string or that + // the previous char is a space, or else we could accidentally + // match "wglFunkywglExtension" with "wglExtension" + + // Also, make sure that the following character is space or null + // or else "wglExtensionTwo" might match "wglExtension" + if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' ')) + return true; // Match + } +} + +static bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat, + bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice) +{ + OpenGLZone aZone; + + HWND hWnd = nullptr; + GLWinWindow glWin; + // Create a temp window to check whether support multi-sample, if support, get the format + if (!InitTempWindow(hWnd, 32, 32, pfd, glWin)) + { + SAL_WARN("vcl.opengl", "Can't create temp window to test"); + return false; + } + + // See if the string exists in WGL + if (!WGLisExtensionSupported("WGL_ARB_multisample")) + { + SAL_WARN("vcl.opengl", "Device doesn't support multisample"); + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return false; + } + // Get our pixel format + PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = reinterpret_cast(wglGetProcAddress("wglChoosePixelFormatARB")); + if (!fn_wglChoosePixelFormatARB) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return false; + } + // Get our current device context + HDC hDC = GetDC(hWnd); + + int pixelFormat; + int valid; + UINT numFormats; + float fAttributes[] = {0,0}; + // These attributes are the bits we want to test for in our sample. + // Everything is pretty standard, the only one we want to + // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB. + // These two are going to do the main testing for whether or not + // we support multisampling on this hardware. + int iAttributes[] = + { + WGL_DOUBLE_BUFFER_ARB,GL_TRUE, + WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, + WGL_SUPPORT_OPENGL_ARB,GL_TRUE, + WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, + WGL_COLOR_BITS_ARB,24, + WGL_ALPHA_BITS_ARB,8, + WGL_DEPTH_BITS_ARB,24, + WGL_STENCIL_BITS_ARB,0, + WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, + WGL_SAMPLES_ARB,8, + 0,0 + }; + + if (!bUseDoubleBufferedRendering) + { + // Use asserts to make sure the iAttributes array is not changed without changing these ugly + // hardcode indexes into it. + assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB); + iAttributes[1] = GL_FALSE; + } + + if (bRequestVirtualDevice) + { + assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB); + iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB; + } + + bool bArbMultisampleSupported = false; + + // First we check to see if we can get a pixel format for 8 samples + valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); + // If we returned true, and our format count is greater than 1 + if (valid && numFormats >= 1) + { + bArbMultisampleSupported = true; + rPixelFormat = pixelFormat; + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return bArbMultisampleSupported; + } + // Our pixel format with 8 samples failed, test for 2 samples + assert(iAttributes[18] == WGL_SAMPLES_ARB); + iAttributes[19] = 2; + valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats); + if (valid && numFormats >= 1) + { + bArbMultisampleSupported = true; + rPixelFormat = pixelFormat; + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + return bArbMultisampleSupported; + } + // Return the valid format + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(glWin.hRC); + ReleaseDC(hWnd, glWin.hDC); + DestroyWindow(hWnd); + + return bArbMultisampleSupported; +} + +namespace +{ + +bool tryShaders(const OUString& rVertexShader, const OUString& rFragmentShader, const OUString& rGeometryShader = "", const OString& rPreamble = "") +{ + GLint nId; + + // Somewhat mysteriously, the OpenGLHelper::LoadShaders() API saves a compiled binary of the + // shader only if you give it the digest of the shaders. We have API to calculate the digest + // only of the combination of vertex and fragment (but not geometry) shader. So if we have a + // geometry shader, we should not save the binary. + if (rGeometryShader.isEmpty()) + { + nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rPreamble, OpenGLHelper::GetDigest( rVertexShader, rFragmentShader, rPreamble)); + } + else + { + assert(rPreamble.isEmpty()); + nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rGeometryShader); + } + if (!nId) + return false; + + // We're interested in the error returned by glDeleteProgram(). + glGetError(); + + glDeleteProgram(nId); + return glGetError() == GL_NO_ERROR; +} + +bool compiledShaderBinariesWork() +{ + static bool bBeenHere = false; + static bool bResult; + + if (bBeenHere) + return bResult; + + bBeenHere = true; + + bResult = + ( +#if 0 // Only look at shaders used by vcl for now + // canvas + tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") && + tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") && + tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") && + tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") && + tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") && + tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") && + // chart2 + (GLEW_VERSION_3_3 ? + (tryShaders("shape3DVertexShader", "shape3DFragmentShader") && + tryShaders("shape3DVertexShaderBatchScroll", "shape3DFragmentShaderBatchScroll") && + tryShaders("shape3DVertexShaderBatch", "shape3DFragmentShaderBatch") && + tryShaders("textVertexShaderBatch", "textFragmentShaderBatch")) : + (tryShaders("shape3DVertexShaderV300", "shape3DFragmentShaderV300"))) && + tryShaders("textVertexShader", "textFragmentShader") && + tryShaders("screenTextVertexShader", "screenTextFragmentShader") && + tryShaders("commonVertexShader", "commonFragmentShader") && + tryShaders("pickingVertexShader", "pickingFragmentShader") && + tryShaders("backgroundVertexShader", "backgroundFragmentShader") && + tryShaders("symbolVertexShader", "symbolFragmentShader") && + tryShaders("symbolVertexShader", "symbolFragmentShader") && + // slideshow + tryShaders("reflectionVertexShader", "reflectionFragmentShader") && + tryShaders("basicVertexShader", "basicFragmentShader") && + tryShaders("vortexVertexShader", "vortexFragmentShader", "vortexGeometryShader") && + tryShaders("basicVertexShader", "rippleFragmentShader") && + tryShaders("glitterVertexShader", "glitterFragmentShader") && + tryShaders("honeycombVertexShader", "honeycombFragmentShader", "honeycombGeometryShader") && +#endif + // vcl + tryShaders("combinedVertexShader", "combinedFragmentShader") && + tryShaders("dumbVertexShader", "invert50FragmentShader") && + tryShaders("textureVertexShader", "areaScaleFragmentShader") && + tryShaders("transformedTextureVertexShader", "maskedTextureFragmentShader") && + tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader") && + tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader", "", "#define MASKED") && + tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader") && + tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader", "", "#define MASKED") && + tryShaders("transformedTextureVertexShader", "textureFragmentShader") && + tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader") && + tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader", "", "// flush shader\n") && + tryShaders("textureVertexShader", "linearGradientFragmentShader") && + tryShaders("textureVertexShader", "radialGradientFragmentShader") && + tryShaders("textureVertexShader", "areaHashCRC64TFragmentShader") && + tryShaders("textureVertexShader", "replaceColorFragmentShader") && + tryShaders("textureVertexShader", "greyscaleFragmentShader") && + tryShaders("textureVertexShader", "textureFragmentShader") && + tryShaders("textureVertexShader", "convolutionFragmentShader") && + tryShaders("textureVertexShader", "areaScaleFastFragmentShader")); + + return bResult; +} + +} // unnamed namespace + +bool WinOpenGLContext::ImplInit() +{ + static bool bFirstCall = true; + + OpenGLZone aZone; + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); + // PixelFormat tells Windows how we want things to be + PIXELFORMATDESCRIPTOR PixelFormatFront = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, // Version Number + PFD_SUPPORT_OPENGL, + PFD_TYPE_RGBA, // Request An RGBA Format + BYTE(32), // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24 bit z-buffer + 8, // stencil buffer + 0, // No Auxiliary Buffer + 0, // now ignored + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER; + PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW; + + // we must check whether can set the MSAA + int WindowPix = 0; + bool bMultiSampleSupport = false; + + if (!mbVCLOnly) + bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, /*bUseDoubleBufferedRendering*/true, false); + else + VCL_GL_INFO("Skipping multisample detection for VCL."); + + if (bMultiSampleSupport && WindowPix != 0) + { + m_aGLWin.bMultiSampleSupported = true; + } + else + { + WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront); +#if OSL_DEBUG_LEVEL > 0 + PIXELFORMATDESCRIPTOR pfd; + DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd); + SAL_WARN("vcl.opengl", "Render Target: Window: " << static_cast((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) << ", Bitmap: " << static_cast((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0)); + SAL_WARN("vcl.opengl", "Supports OpenGL: " << static_cast((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0)); +#endif + } + + if (WindowPix == 0) + { + SAL_WARN("vcl.opengl", "Invalid pixelformat"); + return false; + } + + if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront)) + { + SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError())); + return false; + } + + HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC); + if (hTempRC == nullptr) + { + SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError())); + return false; + } + + if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC)) + { + g_bAnyCurrent = false; + SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError())); + return false; + } + + g_bAnyCurrent = true; + + if (!InitGL()) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(hTempRC); + return false; + } + + HGLRC hSharedCtx = nullptr; + if (!g_vShareList.empty()) + hSharedCtx = g_vShareList.front(); + + if (!wglCreateContextAttribsARB) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(hTempRC); + return false; + } + + // now setup the shared context; this needs a temporary context already + // set up in order to work + int const attribs [] = + { +#ifdef DBG_UTIL + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, +#endif + 0 + }; + m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs); + if (m_aGLWin.hRC == nullptr) + { + SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed: "<< WindowsErrorString(GetLastError())); + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(hTempRC); + return false; + } + + if (!compiledShaderBinariesWork()) + { + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(hTempRC); + return false; + } + + wglMakeCurrent(nullptr, nullptr); + g_bAnyCurrent = false; + wglDeleteContext(hTempRC); + + if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC)) + { + g_bAnyCurrent = false; + SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(GetLastError())); + return false; + } + + g_bAnyCurrent = true; + + if (bFirstCall) + { + // Checking texture size + GLint nMaxTextureSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize); + if (nMaxTextureSize <= 4096) + SAL_WARN("vcl.opengl", "Max texture size is " << nMaxTextureSize + << ". This may not be enough for normal operation."); + else + VCL_GL_INFO("Max texture size: " << nMaxTextureSize); + + // Trying to make a texture and check its size + for (GLint nWidthHeight = 1023; nWidthHeight < nMaxTextureSize; nWidthHeight += (nWidthHeight + 1)) + { + glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, nWidthHeight, nWidthHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, nullptr); + CHECK_GL_ERROR(); + if (glGetError() == GL_NO_ERROR) + { + GLint nWidth = 0; + GLint nHeight = 0; + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &nWidth); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &nHeight); + VCL_GL_INFO("Created texture " << nWidthHeight << "," << nWidthHeight << " reports size: " << nWidth << ", " << nHeight); + } + else + { + SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight << ", " << nWidthHeight << " test texture."); + } + } + } + + InitGLDebugging(); + + g_vShareList.push_back(m_aGLWin.hRC); + + RECT clientRect; + GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect); + m_aGLWin.Width = clientRect.right - clientRect.left; + m_aGLWin.Height = clientRect.bottom - clientRect.top; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + bFirstCall = false; + + static OString aVendor(reinterpret_cast(glGetString(GL_VENDOR))); + + if (aVendor.equalsIgnoreAsciiCase("intel")) + maOpenGLCapabilitySwitch.mbLimitedShaderRegisters = true; + + return true; +} + +OpenGLContext* WinSalInstance::CreateOpenGLContext() +{ + return new WinOpenGLContext; +} + +WinOpenGLSalGraphicsImpl::WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics, + SalGeometryProvider *mpProvider): + OpenGLSalGraphicsImpl(rGraphics,mpProvider), + mrWinParent(rGraphics) +{ +} + +void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) +{ + OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl()); + OpenGLSalGraphicsImpl::DoCopyBits( rPosAry, *pImpl ); +} + +rtl::Reference WinOpenGLSalGraphicsImpl::CreateWinContext() +{ + rtl::Reference xContext(new WinOpenGLContext); + xContext->setVCLOnly(); + if (!xContext->init(mrWinParent.mhLocalDC, mrWinParent.mhWnd)) + { + SAL_WARN("vcl.opengl", "Context could not be created."); + return rtl::Reference(); + } + return rtl::Reference(xContext.get()); +} + +void WinOpenGLSalGraphicsImpl::Init() +{ + if (!IsOffscreen() && mpContext.is() && mpContext->isInitialized()) + { + const GLWinWindow& rGLWindow = static_cast(mpContext->getOpenGLWindow()); + if (rGLWindow.hWnd != mrWinParent.mhWnd || rGLWindow.hDC == mrWinParent.mhLocalDC) + { + // This can legitimately happen, SalFrame keeps 2x + // SalGraphics which share the same hWnd and hDC. + // The shape 'Area' dialog does reparenting to trigger this. + SAL_WARN("vcl.opengl", "Unusual: Windows handle / DC changed without DeInit"); + DeInit(); + } + } + + OpenGLSalGraphicsImpl::Init(); +} + +OpenGLControlsCache::OpenGLControlsCache(): cache(200) {} + +OpenGLControlCacheType & OpenGLControlsCache::get() { + SalData * data = GetSalData(); + if (!data->m_pOpenGLControlsCache) { + data->m_pOpenGLControlsCache.reset(new OpenGLControlsCache); + } + return data->m_pOpenGLControlsCache->cache; +} + +OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height) +: CompatibleDC( rGraphics, x, y, width, height, false ) +{ +} + +OpenGLTexture* OpenGLCompatibleDC::getOpenGLTexture() const +{ + if (!mpImpl) + return nullptr; + + // turn what's in the mpData into a texture + return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData); +} + +std::unique_ptr OpenGLCompatibleDC::getAsMaskTexture() const +{ + auto ret = std::make_unique(); + ret->texture = OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData); + return ret; +} + +bool OpenGLCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture) const +{ + if (!mpImpl) + return false; + + assert(dynamic_cast(&aTexture)); + return static_cast(aTexture).texture.CopyData( + maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, reinterpret_cast(mpData)); +} + +bool WinOpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const & rControlCacheKey, int nX, int nY) +{ + static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); + + if (!gbCacheEnabled) + return false; + + auto & gTextureCache = OpenGLControlsCache::get(); + OpenGLControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey); + + if (iterator == gTextureCache.end()) + return false; + + const std::unique_ptr& pCombo = iterator->second; + + bool bRet = false; + + PreDraw(); + + bRet = RenderTextureCombo(*pCombo, nX, nY); + + PostDraw(); + + return bRet; +} + +bool WinOpenGLSalGraphicsImpl::RenderTextureCombo(TextureCombo const & rCombo, int nX, int nY) +{ + OpenGLTexture& rTexture = *rCombo.mpTexture; + + SalTwoRect aPosAry(0, 0, rTexture.GetWidth(), rTexture.GetHeight(), + nX, nY, rTexture.GetWidth(), rTexture.GetHeight()); + + DrawTextureDiff(rTexture, *rCombo.mpMask, aPosAry, false); + + return true; +} + +bool WinOpenGLSalGraphicsImpl::RenderCompatibleDC(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack, + int nX, int nY, TextureCombo& rCombo) +{ + bool bRet = false; + + PreDraw(); + + rCombo.mpTexture.reset(rWhite.getOpenGLTexture()); + rCombo.mpMask.reset(rBlack.getOpenGLTexture()); + + bRet = RenderTextureCombo(rCombo, nX, nY); + + PostDraw(); + return bRet; +} + +bool WinOpenGLSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, + int nX, int nY , ControlCacheKey& aControlCacheKey) +{ + assert(dynamic_cast(&rWhite)); + assert(dynamic_cast(&rBlack)); + + std::unique_ptr pCombo(new TextureCombo); + + bool bResult = RenderCompatibleDC(static_cast(rWhite), + static_cast(rBlack), nX, nY, *pCombo); + if (!bResult) + return false; + + if (!aControlCacheKey.canCacheControl()) + return true; + + OpenGLControlCachePair pair(aControlCacheKey, std::move(pCombo)); + OpenGLControlsCache::get().insert(std::move(pair)); + + return bResult; +} + +void WinOpenGLSalGraphicsImpl::PreDrawText() +{ + PreDraw(); +} + +void WinOpenGLSalGraphicsImpl::PostDrawText() +{ + PostDraw(); +} + +void WinOpenGLSalGraphicsImpl::DeferredTextDraw(const CompatibleDC::Texture* pTexture, Color aMaskColor, const SalTwoRect& rPosAry) +{ + assert(dynamic_cast(pTexture)); + mpRenderList->addDrawTextureWithMaskColor( + static_cast(pTexture)->texture, aMaskColor, rPosAry); + PostBatchDraw(); +} + +void WinOpenGLSalGraphicsImpl::DrawTextMask( CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry ) +{ + assert(dynamic_cast(pTexture)); + DrawMask( static_cast(pTexture)->texture, nMaskColor, rPosAry ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/winlayout.cxx b/vcl/opengl/win/winlayout.cxx new file mode 100644 index 000000000..59bf12c25 --- /dev/null +++ b/vcl/opengl/win/winlayout.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +bool OpenGLGlobalWinGlyphCache::AllocateTexture(WinGlyphDrawElement& rElement, CompatibleDC* dc) +{ + assert(rElement.maTexture.get() == nullptr); + assert(dynamic_cast(dc)); + OpenGLCompatibleDC* odc = static_cast(dc); + OpenGLCompatibleDC::Texture* texture = new OpenGLCompatibleDC::Texture; + rElement.maTexture.reset(texture); + texture->texture = maPackedTextureAtlas.Reserve(dc->getBitmapWidth(), dc->getBitmapHeight()); + if (!texture->texture) + return false; + if (!odc->copyToTexture(*rElement.maTexture)) + return false; + return true; +} + +void OpenGLGlobalWinGlyphCache::Prune() +{ + std::vector aTextureIDs = maPackedTextureAtlas.ReduceTextureNumber(8); + if (!aTextureIDs.empty()) + { + for (auto& pWinGlyphCache : maWinGlyphCaches) + static_cast(pWinGlyphCache)->RemoveTextures(aTextureIDs); + } +} + +void OpenGLWinGlyphCache::RemoveTextures(std::vector& rTextureIDs) +{ + auto it = maWinTextureCache.begin(); + + while (it != maWinTextureCache.end()) + { + assert(dynamic_cast(it->second.maTexture.get())); + GLuint nTextureID + = static_cast(it->second.maTexture.get())->texture.Id(); + + if (std::find(rTextureIDs.begin(), rTextureIDs.end(), nTextureID) != rTextureIDs.end()) + { + it = maWinTextureCache.erase(it); + } + else + { + ++it; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/x11/X11DeviceInfo.cxx b/vcl/opengl/x11/X11DeviceInfo.cxx new file mode 100644 index 000000000..7f671952f --- /dev/null +++ b/vcl/opengl/x11/X11DeviceInfo.cxx @@ -0,0 +1,363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace glx { + +static int glxtest_pipe = 0; + +static pid_t glxtest_pid = 0; + +} + +pid_t* getGlxPid() +{ + return &glx::glxtest_pid; +} + +int* getGlxPipe() +{ + return &glx::glxtest_pipe; +} + +namespace { + +const char* +strspnp_wrapper(const char* aDelims, const char* aStr) +{ + const char* d; + do + { + for (d = aDelims; *d != '\0'; ++d) + { + if (*aStr == *d) + { + ++aStr; + break; + } + } + } while (*d); + + return aStr; +} + +char* strtok_wrapper(const char* aDelims, char** aStr) +{ + if (!*aStr) + { + return nullptr; + } + + char* ret = const_cast(strspnp_wrapper(aDelims, *aStr)); + + if (!*ret) + { + *aStr = ret; + return nullptr; + } + + char* i = ret; + do + { + for (const char* d = aDelims; *d != '\0'; ++d) + { + if (*i == *d) { + *i = '\0'; + *aStr = ++i; + return ret; + } + } + ++i; + } while (*i); + + *aStr = nullptr; + return ret; +} + +uint64_t version(uint32_t major, uint32_t minor, uint32_t revision = 0) +{ + return (uint64_t(major) << 32) + (uint64_t(minor) << 16) + uint64_t(revision); +} + +} + +X11OpenGLDeviceInfo::X11OpenGLDeviceInfo(): + mbIsMesa(false), + mbIsNVIDIA(false), + mbIsFGLRX(false), + mbIsNouveau(false), + mbIsIntel(false), + mbIsOldSwrast(false), + mbIsLlvmpipe(false), + mnGLMajorVersion(0), + mnMajorVersion(0), + mnMinorVersion(0), + mnRevisionVersion(0) +{ + GetData(); +} + +void X11OpenGLDeviceInfo::GetData() +{ + if (!glx::glxtest_pipe) + return; + + // to understand this function, see bug moz#639842. We retrieve the OpenGL driver information in a + // separate process to protect against bad drivers. + enum { buf_size = 1024 }; + char buf[buf_size]; + ssize_t bytesread = read(glx::glxtest_pipe, + &buf, + buf_size-1); // -1 because we'll append a zero + close(glx::glxtest_pipe); + glx::glxtest_pipe = 0; + + // bytesread < 0 would mean that the above read() call failed. + // This should never happen. If it did, the outcome would be to blacklist anyway. + if (bytesread < 0) + bytesread = 0; + + // let buf be a zero-terminated string + buf[bytesread] = 0; + + // Wait for the glxtest process to finish. This serves 2 purposes: + // * avoid having a zombie glxtest process laying around + // * get the glxtest process status info. + int glxtest_status = 0; + bool wait_for_glxtest_process = true; + bool waiting_for_glxtest_process_failed = false; + int waitpid_errno = 0; + while(wait_for_glxtest_process) + { + wait_for_glxtest_process = false; + if (waitpid(glx::glxtest_pid, &glxtest_status, 0) == -1) + { + waitpid_errno = errno; + if (waitpid_errno == EINTR) + { + wait_for_glxtest_process = true; + } + else + { + // Bug moz#718629 + // ECHILD happens when the glxtest process got reaped got reaped after a PR_CreateProcess + // as per bug moz#227246. This shouldn't matter, as we still seem to get the data + // from the pipe, and if we didn't, the outcome would be to blacklist anyway. + waiting_for_glxtest_process_failed = (waitpid_errno != ECHILD); + } + } + } + + bool exited_with_error_code = !waiting_for_glxtest_process_failed && + WIFEXITED(glxtest_status) && + WEXITSTATUS(glxtest_status) != EXIT_SUCCESS; + bool received_signal = !waiting_for_glxtest_process_failed && + WIFSIGNALED(glxtest_status); + + bool error = waiting_for_glxtest_process_failed || exited_with_error_code || received_signal; + + OString textureFromPixmap; + OString *stringToFill = nullptr; + char *bufptr = buf; + if (!error) + { + while(true) + { + char *line = strtok_wrapper("\n", &bufptr); + if (!line) + break; + if (stringToFill) { + *stringToFill = OString(line); + stringToFill = nullptr; + } + else if(!strcmp(line, "VENDOR")) + stringToFill = &maVendor; + else if(!strcmp(line, "RENDERER")) + stringToFill = &maRenderer; + else if(!strcmp(line, "VERSION")) + stringToFill = &maVersion; + else if(!strcmp(line, "TFP")) + stringToFill = &textureFromPixmap; + } + } + + // only useful for Linux kernel version check for FGLRX driver. + // assumes X client == X server, which is sad. + struct utsname unameobj; + if (!uname(&unameobj)) + { + maOS = OString(unameobj.sysname); + maOSRelease = OString(unameobj.release); + } + + // determine the major OpenGL version. That's the first integer in the version string. + mnGLMajorVersion = strtol(maVersion.getStr(), nullptr, 10); + + // determine driver type (vendor) and where in the version string + // the actual driver version numbers should be expected to be found (whereToReadVersionNumbers) + const char *whereToReadVersionNumbers = nullptr; + const char *Mesa_in_version_string = strstr(maVersion.getStr(), "Mesa"); + if (Mesa_in_version_string) + { + mbIsMesa = true; + // with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get: + // there is no actual driver version info. + whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa"); + if (strcasestr(maVendor.getStr(), "nouveau")) + mbIsNouveau = true; + if (strcasestr(maRenderer.getStr(), "intel")) // yes, intel is in the renderer string + mbIsIntel = true; + if (strcasestr(maRenderer.getStr(), "llvmpipe")) + mbIsLlvmpipe = true; + if (strcasestr(maRenderer.getStr(), "software rasterizer")) + mbIsOldSwrast = true; + } + else if (strstr(maVendor.getStr(), "NVIDIA Corporation")) + { + mbIsNVIDIA = true; + // with the NVIDIA driver, the version string contains "NVIDIA major.minor" + // note that here the vendor and version strings behave differently, that's why we don't put this above + // alongside Mesa_in_version_string. + const char *NVIDIA_in_version_string = strstr(maVersion.getStr(), "NVIDIA"); + if (NVIDIA_in_version_string) + whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA"); + } + else if (strstr(maVendor.getStr(), "ATI Technologies Inc")) + { + mbIsFGLRX = true; + // with the FGLRX driver, the version string only gives an OpenGL version: so let's return that. + // that can at least give a rough idea of how old the driver is. + whereToReadVersionNumbers = maVersion.getStr(); + } + + // read major.minor version numbers of the driver (not to be confused with the OpenGL version) + if (whereToReadVersionNumbers) + { + // copy into writable buffer, for tokenization + strncpy(buf, whereToReadVersionNumbers, buf_size-1); + buf[buf_size-1] = 0; + bufptr = buf; + + // now try to read major.minor version numbers. In case of failure, gracefully exit: these numbers have + // been initialized as 0 anyways + char *token = strtok_wrapper(".", &bufptr); + if (token) + { + mnMajorVersion = strtol(token, nullptr, 10); + token = strtok_wrapper(".", &bufptr); + if (token) + { + mnMinorVersion = strtol(token, nullptr, 10); + token = strtok_wrapper(".", &bufptr); + if (token) + mnRevisionVersion = strtol(token, nullptr, 10); + } + } + } +} + +bool X11OpenGLDeviceInfo::isDeviceBlocked() +{ + // don't even try to use OpenGL 1.x + if (mnGLMajorVersion == 1) + return true; + + CrashReporter::addKeyValue("AdapterVendorId", OStringToOUString(maVendor, RTL_TEXTENCODING_UTF8), CrashReporter::AddItem); + CrashReporter::addKeyValue("AdapterDeviceId", OStringToOUString(maRenderer, RTL_TEXTENCODING_UTF8), CrashReporter::Write); + + SAL_INFO("vcl.opengl", "Vendor: " << maVendor); + SAL_INFO("vcl.opengl", "Renderer: " << maRenderer); + SAL_INFO("vcl.opengl", "Version: " << maVersion); + SAL_INFO("vcl.opengl", "OS: " << maOS); + SAL_INFO("vcl.opengl", "OSRelease: " << maOSRelease); + + if (mbIsMesa) + { + if (mbIsNouveau && version(mnMajorVersion, mnMinorVersion) < version(8,0)) + { + SAL_WARN("vcl.opengl", "blocked driver version: old nouveau driver (requires mesa 8.0+)"); + return true; + } + else if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(7,10,3)) + { + SAL_WARN("vcl.opengl", "blocked driver version: requires at least mesa 7.10.3"); + return true; + } + else if (mbIsIntel && version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) == version(9,0,2)) + { + SAL_WARN("vcl.opengl", "blocked driver version: my broken intel driver Mesa 9.0.2"); + return true; + } + else if (mbIsOldSwrast) + { + SAL_WARN("vcl.opengl", "blocked driver version: software rasterizer"); + return true; + } + else if (mbIsLlvmpipe && version(mnMajorVersion, mnMinorVersion) < version(9, 1)) + { + // bug moz#791905, Mesa bug 57733, fixed in Mesa 9.1 according to + // https://bugs.freedesktop.org/show_bug.cgi?id=57733#c3 + SAL_WARN("vcl.opengl", "blocked driver version: fdo#57733"); + return true; + } + } + else if (mbIsNVIDIA) + { + if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(257,21)) + { + SAL_WARN("vcl.opengl", "blocked driver version: nvidia requires at least 257.21"); + return true; + } + } + else if (mbIsFGLRX) + { + // FGLRX does not report a driver version number, so we have the OpenGL version instead. + // by requiring OpenGL 3, we effectively require recent drivers. + if (version(mnMajorVersion, mnMinorVersion, mnRevisionVersion) < version(3, 0)) + { + SAL_WARN("vcl.opengl", "blocked driver version: require at least OpenGL 3 for fglrx"); + return true; + } + // Bug moz#724640: FGLRX + Linux 2.6.32 is a crashy combo + bool unknownOS = maOS.isEmpty() || maOSRelease.isEmpty(); + bool badOS = maOS.indexOf("Linux") != -1 && + maOSRelease.indexOf("2.6.32") != -1; + if (unknownOS || badOS) + { + SAL_WARN("vcl.opengl", "blocked OS version with fglrx"); + return true; + } + } + else + { + // like on windows, let's block unknown vendors. Think of virtual machines. + // Also, this case is hit whenever the GLXtest probe failed to get driver info or crashed. + SAL_WARN("vcl.opengl", "unknown vendor => blocked"); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/x11/cairotextrender.cxx b/vcl/opengl/x11/cairotextrender.cxx new file mode 100644 index 000000000..39b5f661d --- /dev/null +++ b/vcl/opengl/x11/cairotextrender.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include + +OpenGLX11CairoTextRender::OpenGLX11CairoTextRender(X11SalGraphics& rParent) + : X11CairoTextRender(rParent) +{ +} + +cairo_t* OpenGLX11CairoTextRender::getCairoContext() +{ + cairo_surface_t* surface = nullptr; + OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); + if( pImpl ) + { + tools::Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + if( aClipRect.GetWidth() == 0 || aClipRect.GetHeight() == 0 ) + { + aClipRect.setWidth( GetWidth() ); + aClipRect.setHeight( GetHeight() ); + } + surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, aClipRect.GetWidth(), aClipRect.GetHeight() ); + } + if (!surface) + return nullptr; + cairo_t *cr = cairo_create(surface); + cairo_surface_destroy(surface); + return cr; +} + +void OpenGLX11CairoTextRender::getSurfaceOffset( double& nDX, double& nDY ) +{ + OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); + if( pImpl ) + { + tools::Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + nDX = -aClipRect.Left(); + nDY = -aClipRect.Top(); + } +} + +void OpenGLX11CairoTextRender::releaseCairoContext(cairo_t* cr) +{ + // XXX: lfrb: GLES 2.0 doesn't support GL_UNSIGNED_INT_8_8_8_8_REV + OpenGLSalGraphicsImpl *pImpl = dynamic_cast< OpenGLSalGraphicsImpl* >(mrParent.GetImpl()); + if(!pImpl) + { + cairo_destroy(cr); + return; + } + + cairo_surface_t* pSurface = cairo_get_target(cr); + int nWidth = cairo_image_surface_get_width( pSurface ); + int nHeight = cairo_image_surface_get_height( pSurface ); + cairo_surface_flush(pSurface); + unsigned char *pSrc = cairo_image_surface_get_data( pSurface ); + + // XXX: lfrb: GLES 2.0 doesn't support GL_UNSIGNED_INT_8_8_8_8_REV + tools::Rectangle aClipRect = pImpl->getClipRegion().GetBoundRect(); + + SalTwoRect aRect(0, 0, nWidth, nHeight, + aClipRect.Left(), aClipRect.Top(), nWidth, nHeight); + + // Cairo surface data is ARGB with premultiplied alpha and is Y-inverted + OpenGLTexture aTexture( nWidth, nHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pSrc ); + pImpl->PreDraw(); + pImpl->DrawAlphaTexture( aTexture, aRect, true, true ); + pImpl->PostDraw(); + + cairo_destroy(cr); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx new file mode 100644 index 000000000..c00ff76e8 --- /dev/null +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +static std::vector g_vShareList; +static bool g_bAnyCurrent; + +namespace { + +class X11OpenGLContext : public OpenGLContext +{ +public: + void init(Display* dpy, Window win, int screen); + virtual void initWindow() override; +private: + GLX11Window m_aGLWin; + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } + virtual bool ImplInit() override; + void initGLWindow(Visual* pVisual); + virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual bool isCurrent() override; + virtual bool isAnyCurrent() override; + virtual void sync() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +#ifdef DBG_UTIL + int unxErrorHandler(Display* dpy, XErrorEvent* event) + { + char err[256]; + char req[256]; + char minor[256]; + XGetErrorText(dpy, event->error_code, err, 256); + XGetErrorText(dpy, event->request_code, req, 256); + XGetErrorText(dpy, event->minor_code, minor, 256); + SAL_WARN("vcl.opengl", "Error: " << err << ", Req: " << req << ", Minor: " << minor); + return 0; + } +#endif + + typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); + + class TempErrorHandler + { + private: + errorHandler oldErrorHandler; + Display* mdpy; + + public: + TempErrorHandler(Display* dpy, errorHandler newErrorHandler) + : oldErrorHandler(nullptr) + , mdpy(dpy) + { + if (mdpy) + { + XLockDisplay(dpy); + XSync(dpy, false); + oldErrorHandler = XSetErrorHandler(newErrorHandler); + } + } + + ~TempErrorHandler() + { + if (mdpy) + { + // sync so that we possibly get an XError + glXWaitGL(); + XSync(mdpy, false); + XSetErrorHandler(oldErrorHandler); + XUnlockDisplay(mdpy); + } + } + }; + + static bool errorTriggered; + int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ ) + { + errorTriggered = true; + + return 0; + } + + GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC) + { + OpenGLZone aZone; + + if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) + return nullptr; + + VCL_GL_INFO("window: " << win); + + XWindowAttributes xattr; + if( !XGetWindowAttributes( dpy, win, &xattr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win); + xattr.screen = nullptr; + xattr.visual = nullptr; + } + + int screen = XScreenNumberOfScreen( xattr.screen ); + + // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */ + static int visual_attribs[] = + { + GLX_DOUBLEBUFFER, True, + GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + None + }; + + int fbCount = 0; + GLXFBConfig* pFBC = glXChooseFBConfig( dpy, + screen, + visual_attribs, &fbCount ); + + if(!pFBC) + { + SAL_WARN("vcl.opengl", "no suitable fb format found"); + return nullptr; + } + + int best_num_samp = -1; + for(int i = 0; i < fbCount; ++i) + { + XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] ); + if(pVi && (xattr.visual && pVi->visualid == xattr.visual->visualid) ) + { + // pick the one with the most samples per pixel + int nSampleBuf = 0; + int nSamples = 0; + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf ); + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples ); + + if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) ) + { + nBestFBC = i; + best_num_samp = nSamples; + } + } + XFree( pVi ); + } + + return pFBC; + } + + Visual* getVisual(Display* dpy, Window win) + { + OpenGLZone aZone; + + XWindowAttributes xattr; + if( !XGetWindowAttributes( dpy, win, &xattr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win); + xattr.visual = nullptr; + } + VCL_GL_INFO("using VisualID " << xattr.visual); + return xattr.visual; + } +} + +void X11OpenGLContext::sync() +{ + OpenGLZone aZone; + glXWaitGL(); + XSync(m_aGLWin.dpy, false); +} + +void X11OpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); + + BuffersSwapped(); +} + +void X11OpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + if (m_aGLWin.dpy) + { + glXMakeCurrent(m_aGLWin.dpy, None, nullptr); + g_bAnyCurrent = false; + } +} + +bool X11OpenGLContext::isCurrent() +{ + OpenGLZone aZone; + return g_bAnyCurrent && m_aGLWin.ctx && glXGetCurrentContext() == m_aGLWin.ctx && + glXGetCurrentDrawable() == m_aGLWin.win; +} + +bool X11OpenGLContext::isAnyCurrent() +{ + return g_bAnyCurrent && glXGetCurrentContext() != None; +} + +SystemWindowData X11OpenGLContext::generateWinData(vcl::Window* pParent, bool /*bRequestLegacyContext*/) +{ + OpenGLZone aZone; + + SystemWindowData aWinData; + aWinData.pVisual = nullptr; + aWinData.bClipUsingNativeWidget = false; + + const SystemEnvData* sysData(pParent->GetSystemData()); + + Display *dpy = static_cast(sysData->pDisplay); + Window win = sysData->aWindow; + + if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) ) + return aWinData; + + int best_fbc = -1; + GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc); + + if (!pFBC) + return aWinData; + + XVisualInfo* vi = nullptr; + if( best_fbc != -1 ) + vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] ); + + XFree(pFBC); + + if( vi ) + { + VCL_GL_INFO("using VisualID " << vi->visualid); + aWinData.pVisual = static_cast(vi->visual); + } + + return aWinData; +} + +bool X11OpenGLContext::ImplInit() +{ + if (!m_aGLWin.dpy) + return false; + + OpenGLZone aZone; + + GLXContext pSharedCtx( nullptr ); +#ifdef DBG_UTIL + TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); +#endif + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); + + if (!g_vShareList.empty()) + pSharedCtx = g_vShareList.front(); + + //tdf#112166 for, e.g. VirtualBox GL, claiming OpenGL 2.1 + static bool hasCreateContextAttribsARB = glXGetProcAddress(reinterpret_cast("glXCreateContextAttribsARB")) != nullptr; + if (hasCreateContextAttribsARB && !mbRequestLegacyContext) + { + int best_fbc = -1; + GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc); + + if (pFBC && best_fbc != -1) + { + int const pContextAttribs[] = + { +#if 0 // defined(DBG_UTIL) + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, +#endif + None + + }; + m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, /* direct, not via X */ GL_TRUE, pContextAttribs); + SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context"); + } + else + SAL_WARN("vcl.opengl", "unable to find correct FBC"); + } + + if (!m_aGLWin.ctx) + { + if (!m_aGLWin.vi) + return false; + + SAL_WARN("vcl.opengl", "attempting to create a non-double-buffered " + "visual matching the context"); + + m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy, + m_aGLWin.vi, + pSharedCtx, + GL_TRUE /* direct, not via X server */); + } + + if( m_aGLWin.ctx ) + { + g_vShareList.push_back( m_aGLWin.ctx ); + } + else + { + SAL_WARN("vcl.opengl", "unable to create GLX context"); + return false; + } + + if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) ) + { + g_bAnyCurrent = false; + SAL_WARN("vcl.opengl", "unable to select current GLX context"); + return false; + } + + g_bAnyCurrent = true; + + int glxMinor, glxMajor; + double nGLXVersion = 0; + if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) + nGLXVersion = glxMajor + 0.1*glxMinor; + SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion); + + SAL_INFO("vcl.opengl", "available GL extensions: " << glGetString(GL_EXTENSIONS)); + + XWindowAttributes aWinAttr; + if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &aWinAttr ) ) + { + SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin.win); + m_aGLWin.Width = 0; + m_aGLWin.Height = 0; + } + else + { + m_aGLWin.Width = aWinAttr.width; + m_aGLWin.Height = aWinAttr.height; + } + + if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) + { + // enable vsync + typedef GLint (*glXSwapIntervalProc)(GLint); + glXSwapIntervalProc glXSwapInterval = reinterpret_cast(glXGetProcAddress( reinterpret_cast("glXSwapIntervalSGI") )); + if( glXSwapInterval ) + { + TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler); + + errorTriggered = false; + + glXSwapInterval( 1 ); + + if( errorTriggered ) + SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?"); + else + VCL_GL_INFO("set swap interval to 1 (enable vsync)"); + } + } + + bool bRet = InitGL(); + InitGLDebugging(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + return bRet; +} + +void X11OpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + +#ifdef DBG_UTIL + TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler); +#endif + + if (m_aGLWin.dpy) + { + if (!glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx )) + { + g_bAnyCurrent = false; + SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed " + "on drawable " << m_aGLWin.win); + return; + } + g_bAnyCurrent = true; + } + + registerAsCurrent(); +} + +void X11OpenGLContext::destroyCurrentContext() +{ + if(m_aGLWin.ctx) + { + std::vector::iterator itr = std::remove( g_vShareList.begin(), g_vShareList.end(), m_aGLWin.ctx ); + if (itr != g_vShareList.end()) + g_vShareList.erase(itr); + + glXMakeCurrent(m_aGLWin.dpy, None, nullptr); + g_bAnyCurrent = false; + if( glGetError() != GL_NO_ERROR ) + { + SAL_WARN("vcl.opengl", "glError: " << glGetError()); + } + glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); + m_aGLWin.ctx = nullptr; + } +} + +void X11OpenGLContext::init(Display* dpy, Window win, int screen) +{ + if (isInitialized()) + return; + + if (!dpy) + return; + + OpenGLZone aZone; + + m_aGLWin.dpy = dpy; + m_aGLWin.win = win; + m_aGLWin.screen = screen; + + Visual* pVisual = getVisual(dpy, win); + + initGLWindow(pVisual); + + ImplInit(); +} + +void X11OpenGLContext::initGLWindow(Visual* pVisual) +{ + OpenGLZone aZone; + + // Get visual info + { + XVisualInfo aTemplate; + aTemplate.visualid = XVisualIDFromVisual( pVisual ); + int nVisuals = 0; + XVisualInfo* pInfo = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals ); + if( nVisuals != 1 ) + SAL_WARN( "vcl.opengl", "match count for visual id is not 1" ); + m_aGLWin.vi = pInfo; + } + + // Check multisample support + /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks + * an FBConfig instead ... */ + int nSamples = 0; + glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples); + if( nSamples > 0 ) + m_aGLWin.bMultiSampleSupported = true; + + m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen ); + SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions); +} + +void X11OpenGLContext::initWindow() +{ + const SystemEnvData* pChildSysData = nullptr; + SystemWindowData winData = generateWinData(mpWindow, false); + if( winData.pVisual ) + { + if( !m_pChildWindow ) + { + m_pChildWindow = VclPtr::Create(mpWindow, 0, &winData, false); + } + pChildSysData = m_pChildWindow->GetSystemData(); + } + + if (!m_pChildWindow || !pChildSysData) + return; + + InitChildWindow(m_pChildWindow.get()); + + m_aGLWin.dpy = static_cast(pChildSysData->pDisplay); + m_aGLWin.win = pChildSysData->aWindow; + m_aGLWin.screen = pChildSysData->nScreen; + + Visual* pVisual = static_cast(pChildSysData->pVisual); + initGLWindow(pVisual); +} + +GLX11Window::GLX11Window() + : dpy(nullptr) + , screen(0) + , win(0) + , vi(nullptr) + , ctx(nullptr) +{ +} + +bool GLX11Window::HasGLXExtension( const char* name ) const +{ + for (sal_Int32 i = 0; i != -1;) { + if (GLXExtensions.getToken(0, ' ', i) == name) { + return true; + } + } + return false; +} + +GLX11Window::~GLX11Window() +{ + XFree(vi); +} + +bool GLX11Window::Synchronize(bool bOnoff) const +{ + XSynchronize(dpy, bOnoff); + return true; +} + +OpenGLContext* X11SalInstance::CreateOpenGLContext() +{ + return new X11OpenGLContext; +} + +X11OpenGLSalGraphicsImpl::X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ): + OpenGLSalGraphicsImpl(rParent,rParent.GetGeometryProvider()), + mrX11Parent(rParent) +{ +} + +X11OpenGLSalGraphicsImpl::~X11OpenGLSalGraphicsImpl() +{ +} + +void X11OpenGLSalGraphicsImpl::Init() +{ + // The m_pFrame and m_pVDev pointers are updated late in X11 + mpProvider = mrX11Parent.GetGeometryProvider(); + OpenGLSalGraphicsImpl::Init(); +} + +rtl::Reference X11OpenGLSalGraphicsImpl::CreateWinContext() +{ + NativeWindowHandleProvider *pProvider = dynamic_cast(mrX11Parent.m_pFrame); + + if( !pProvider ) + return nullptr; + + sal_uIntPtr aWin = pProvider->GetNativeWindowHandle(); + rtl::Reference xContext = new X11OpenGLContext; + xContext->setVCLOnly(); + xContext->init( mrX11Parent.GetXDisplay(), aWin, + mrX11Parent.m_nXScreen.getXScreen() ); + return rtl::Reference(xContext.get()); +} + +void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) +{ + OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrX11Parent.GetImpl()); + OpenGLSalGraphicsImpl::DoCopyBits( rPosAry, *pImpl ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/x11/salvd.cxx b/vcl/opengl/x11/salvd.cxx new file mode 100644 index 000000000..a6ed5602f --- /dev/null +++ b/vcl/opengl/x11/salvd.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include + +#include + +void X11SalGraphics::Init( X11OpenGLSalVirtualDevice *pDevice ) +{ + SalDisplay *pDisplay = pDevice->GetDisplay(); + + m_nXScreen = pDevice->GetXScreenNumber(); + m_pColormap = &pDisplay->GetColormap( m_nXScreen ); + + m_pVDev = pDevice; + m_pFrame = nullptr; + + bWindow_ = pDisplay->IsDisplay(); + bVirDev_ = true; + + mxImpl->Init(); +} + +X11OpenGLSalVirtualDevice::X11OpenGLSalVirtualDevice( SalGraphics const * pGraphics, + long nDX, long nDY, + const SystemGraphicsData *pData, + std::unique_ptr pNewGraphics) : + mpGraphics(std::move(pNewGraphics)), + mbGraphics( false ), + mnXScreen( 0 ) +{ + assert(mpGraphics); + + // TODO Check where a VirtualDevice is created from SystemGraphicsData + assert( pData == nullptr ); (void)pData; + + mpDisplay = vcl_sal::getSalDisplay(GetGenericUnixSalData()); + mnXScreen = pGraphics ? static_cast(pGraphics)->GetScreenNumber() : + vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDefaultXScreen(); + mnWidth = nDX; + mnHeight = nDY; + mpGraphics->Init( this ); +} + +X11OpenGLSalVirtualDevice::~X11OpenGLSalVirtualDevice() +{ +} + +SalGraphics* X11OpenGLSalVirtualDevice::AcquireGraphics() +{ + if( mbGraphics ) + return nullptr; + + if( mpGraphics ) + mbGraphics = true; + + return mpGraphics.get(); +} + +void X11OpenGLSalVirtualDevice::ReleaseGraphics( SalGraphics* ) +{ + mbGraphics = false; +} + + +bool X11OpenGLSalVirtualDevice::SetSize( long nDX, long nDY ) +{ + if( !nDX ) nDX = 1; + if( !nDY ) nDY = 1; + + mnWidth = nDX; + mnHeight = nDY; + if( mpGraphics ) + mpGraphics->Init( this ); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DataFlavorMapping.cxx b/vcl/osx/DataFlavorMapping.cxx new file mode 100644 index 000000000..dfba27d20 --- /dev/null +++ b/vcl/osx/DataFlavorMapping.cxx @@ -0,0 +1,747 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "DataFlavorMapping.hxx" +#include "HtmlFmtFlt.hxx" +#include "PictToBmpFlt.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace cppu; +using namespace std; + +namespace +{ + /* 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 == cppu::UnoType>::get()) || (dtype == cppu::UnoType::get()))); + } + + OUString NSStringToOUString( const NSString* cfString) + { + 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]; + } + + NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star Object Descriptor (XML)\""; + NSString* PBTYPE_SESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + NSString* PBTYPE_SLSDX = @"application/x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link Source Descriptor (XML)\""; + NSString* PBTYPE_ESX = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\""; + NSString* PBTYPE_LSX = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\""; + NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\""; + NSString* PBTYPE_SVXB = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\""; + NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\""; + NSString* PBTYPE_WMF = @"application/x-openoffice-wmf;windows_formatname=\"Image WMF\""; + NSString* PBTYPE_EMF = @"application/x-openoffice-emf;windows_formatname=\"Image EMF\""; + + 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 + { + const NSString* SystemFlavor; + const char* OOoFlavor; + const char* HumanPresentableName; + bool DataTypeOUString; // sequence otherwise + }; + + /* At the moment it appears as if only MS Office pastes "public.html" to the clipboard. + */ + static const FlavorMap flavorMap[] = + { + { NSPasteboardTypeString, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true }, + { NSPasteboardTypeRTF, "text/rtf", "Rich Text Format", false }, + { NSPasteboardTypePDF, "application/pdf", "PDF File", false }, + { NSPasteboardTypeTIFF, "image/png", "Portable Network Graphics", false }, + { NSPasteboardTypeHTML, "text/html", "Plain Html", false }, +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create + // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead" + { NSFilenamesPboardType, "application/x-openoffice-filelist;windows_formatname=\"FileList\"", "FileList", false }, +SAL_WNODEPRECATED_DECLARATIONS_POP + { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", false }, + { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false }, + { PBTYPE_ESX, FLAVOR_ESX, "Star Embed Source (XML)", false }, + { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", false }, + { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", false }, + { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false }, + { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", false }, + { PBTYPE_WMF, FLAVOR_WMF, "Windows MetaFile", false }, + { PBTYPE_EMF, FLAVOR_EMF, "Windows Enhanced MetaFile", false }, + { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", false }, + { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data",false } + }; + + #define SIZE_FLAVOR_MAP (sizeof(flavorMap)/sizeof(FlavorMap)) + + bool isByteSequenceType(const Type& theType) + { + return (theType == cppu::UnoType>::get()); + } + + bool isOUStringType(const Type& theType) + { + return (theType == cppu::UnoType::get() ); + } + +/* A base class for other data provider. + */ +class DataProviderBaseImpl : public DataProvider +{ +public: + DataProviderBaseImpl(const Any& data); + DataProviderBaseImpl(id data); + virtual ~DataProviderBaseImpl() override; + +protected: + Any mData; + //NSData* mSystemData; + id mSystemData; +}; + +} // unnamed namespace + +DataProviderBaseImpl::DataProviderBaseImpl(const Any& data) : + mData(data), + mSystemData(nil) +{ +} + +DataProviderBaseImpl::DataProviderBaseImpl(id data) : + mSystemData(data) +{ + [mSystemData retain]; +} + +DataProviderBaseImpl::~DataProviderBaseImpl() +{ + if (mSystemData) + { + [mSystemData release]; + } +} + +namespace { + +class UniDataProvider : public DataProviderBaseImpl +{ +public: + UniDataProvider(const Any& data); + + UniDataProvider(NSData* data); + + virtual NSData* getSystemData() override; + + virtual Any getOOoData() override; +}; + +} + +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 <<= OUString(static_cast([mSystemData bytes]), + [mSystemData length], + RTL_TEXTENCODING_UTF8); + } + else + { + oOOData = mData; + } + + return oOOData; +} + +namespace { + +class ByteSequenceDataProvider : public DataProviderBaseImpl +{ +public: + ByteSequenceDataProvider(const Any& data); + + ByteSequenceDataProvider(NSData* data); + + virtual NSData* getSystemData() override; + + virtual Any getOOoData() override; +}; + +} + +ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data) : + DataProviderBaseImpl(data) +{ +} + +ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* ByteSequenceDataProvider::getSystemData() +{ + Sequence rawData; + mData >>= rawData; + + return [NSData dataWithBytes: rawData.getArray() length: rawData.getLength()]; +} + +Any ByteSequenceDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence byteSequence; + byteSequence.realloc(flavorDataLength); + memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength); + oOOData <<= byteSequence; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +namespace { + +class HTMLFormatDataProvider : public DataProviderBaseImpl +{ +public: + HTMLFormatDataProvider(NSData* data); + + virtual NSData* getSystemData() override; + + virtual Any getOOoData() override; +}; + +} + +HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data) : + DataProviderBaseImpl(data) +{ +} + +NSData* HTMLFormatDataProvider::getSystemData() +{ + Sequence textHtmlData; + mData >>= textHtmlData; + + Sequence htmlFormatData = TextHtmlToHTMLFormat(textHtmlData); + + return [NSData dataWithBytes: htmlFormatData.getArray() length: htmlFormatData.getLength()]; +} + +Any HTMLFormatDataProvider::getOOoData() +{ + Any oOOData; + + if (mSystemData) + { + unsigned int flavorDataLength = [mSystemData length]; + Sequence unkHtmlData; + + unkHtmlData.realloc(flavorDataLength); + memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength); + + Sequence* pPlainHtml = &unkHtmlData; + Sequence plainHtml; + + if (isHTMLFormat(unkHtmlData)) + { + plainHtml = HTMLFormatToTextHtml(unkHtmlData); + pPlainHtml = &plainHtml; + } + + oOOData <<= *pPlainHtml; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +namespace { + + +class PNGDataProvider : public DataProviderBaseImpl +{ + NSBitmapImageFileType meImageType; +public: + PNGDataProvider( const Any&, NSBitmapImageFileType); + + PNGDataProvider( NSData*, NSBitmapImageFileType); + + virtual NSData* getSystemData() override; + + virtual Any getOOoData() override; +}; + +} + +PNGDataProvider::PNGDataProvider( const Any& data, NSBitmapImageFileType eImageType) : + DataProviderBaseImpl(data), + meImageType( eImageType ) +{ +} + +PNGDataProvider::PNGDataProvider( NSData* data, NSBitmapImageFileType eImageType) : + DataProviderBaseImpl(data), + meImageType( eImageType ) +{ +} + +NSData* PNGDataProvider::getSystemData() +{ + Sequence pngData; + mData >>= pngData; + + Sequence imgData; + NSData* sysData = nullptr; + if( PNGToImage( pngData, imgData, meImageType)) + sysData = [NSData dataWithBytes: imgData.getArray() length: imgData.getLength()]; + + return sysData; +} + +/* The AOO 'PCT' filter is not yet good enough to be used + and there is no flavor defined for exchanging 'PCT' with AOO + so we convert 'PCT' to a PNG and provide this to AOO +*/ +Any PNGDataProvider::getOOoData() +{ + Any oOOData; + + if( mSystemData) + { + const unsigned int flavorDataLength = [mSystemData length]; + Sequence imgData( flavorDataLength); + memcpy( imgData.getArray(), [mSystemData bytes], flavorDataLength); + + Sequence pngData; + if( ImageToPNG( imgData, pngData)) + oOOData <<= pngData; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +namespace { + +class FileListDataProvider : public DataProviderBaseImpl +{ +public: + FileListDataProvider(const Any& data); + FileListDataProvider(NSArray* data); + + virtual NSData* getSystemData() override; + virtual Any getOOoData() override; +}; + +} + +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 oOOFileList(lenSeqRequired); + unichar* pBuffer = reinterpret_cast(oOOFileList.getArray()); + memset(pBuffer, 0, 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 <<= oOOFileList; + } + else + { + oOOData = mData; + } + + return oOOData; +} + +DataFlavorMapper::DataFlavorMapper() +{ + Reference xContext = comphelper::getProcessComponentContext(); + mrXMimeCntFactory = MimeContentTypeFactory::create( xContext ); +} + +DataFlavorMapper::~DataFlavorMapper() +{ + // release potential NSStrings + for( OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end(); ++it ) + { + [it->second release]; + it->second = nil; + } +} + +DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor( const NSString* systemDataFlavor) const +{ + DataFlavor oOOFlavor; + + for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++) + { + if ([systemDataFlavor caseInsensitiveCompare:const_cast(flavorMap[i].SystemFlavor)] == NSOrderedSame) + { + oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor); + oOOFlavor.HumanPresentableName = OUString::createFromAscii(flavorMap[i].HumanPresentableName); + oOOFlavor.DataType = flavorMap[i].DataTypeOUString ? cppu::UnoType::get() : cppu::UnoType>::get(); + return oOOFlavor; + } + } // for + + // look if this might be an internal type; if it comes in here it must have + // been through openOfficeToSystemFlavor before, so it should then be in the map + OUString aTryFlavor( NSStringToOUString( systemDataFlavor ) ); + if( maOfficeOnlyTypes.find( aTryFlavor ) != maOfficeOnlyTypes.end() ) + { + oOOFlavor.MimeType = aTryFlavor; + oOOFlavor.HumanPresentableName.clear(); + oOOFlavor.DataType = cppu::UnoType>::get(); + } + + return oOOFlavor; +} + +const NSString* DataFlavorMapper::openOfficeToSystemFlavor( const DataFlavor& oOOFlavor, bool& rbInternal) const +{ + const NSString* sysFlavor = nullptr; + rbInternal = false; + + for( size_t i = 0; i < SIZE_FLAVOR_MAP; ++i ) + { + if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor))) + { + sysFlavor = flavorMap[i].SystemFlavor; + } + } + + if(!sysFlavor) + { + rbInternal = true; + OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find( oOOFlavor.MimeType ); + + if( it == maOfficeOnlyTypes.end() ) + sysFlavor = maOfficeOnlyTypes[ oOOFlavor.MimeType ] = OUStringToNSString( oOOFlavor.MimeType ); + else + sysFlavor = it->second; + } + + return sysFlavor; +} + +NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard) +{ + NSArray *supportedTypes = [NSArray arrayWithObjects: NSPasteboardTypeTIFF, nil]; + NSString *sysFlavor = [pPasteboard availableTypeFromArray:supportedTypes]; + return sysFlavor; +} + +DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, Reference const & rTransferable) const +{ + DataProviderPtr_t dp; + + try + { + DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor); + + Any data = rTransferable->getTransferData(oOOFlavor); + + if (isByteSequenceType(data.getValueType())) + { + /* + the HTMLFormatDataProvider prepends segment information to HTML + this is useful for exchange with MS Word (which brings this stuff from Windows) + but annoying for other applications. Since this extension is not a standard datatype + on the Mac, let us not provide but provide normal HTML + + if ([systemFlavor caseInsensitiveCompare: NSHTMLPboardType] == NSOrderedSame) + { + dp = DataProviderPtr_t(new HTMLFormatDataProvider(data)); + } + else + */ + if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeTIFF] == NSOrderedSame) + { + dp = DataProviderPtr_t( new PNGDataProvider( data, NSBitmapImageFileTypeTIFF)); + } +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create + // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead" + else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) +SAL_WNODEPRECATED_DECLARATIONS_POP + { + dp = DataProviderPtr_t(new FileListDataProvider(data)); + } + else + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(data)); + } + } + else // Must be OUString type + { + SAL_WARN_IF( + !isOUStringType(data.getValueType()), "vcl", + "must be OUString type"); + 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) +{ + return DataProviderPtr_t(new FileListDataProvider(systemData)); +} + +DataProviderPtr_t DataFlavorMapper::getDataProvider( const NSString* systemFlavor, NSData* systemData) +{ + DataProviderPtr_t dp; + + if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeString] == NSOrderedSame) + { + dp = DataProviderPtr_t(new UniDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeHTML] == NSOrderedSame) + { + dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData)); + } + else if ([systemFlavor caseInsensitiveCompare: NSPasteboardTypeTIFF] == NSOrderedSame) + { + dp = DataProviderPtr_t( new PNGDataProvider(systemData, NSBitmapImageFileTypeTIFF)); + } +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create multiple + // pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead" + else if ([systemFlavor caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) +SAL_WNODEPRECATED_DECLARATIONS_POP + { + //dp = DataProviderPtr_t(new FileListDataProvider(systemData)); + } + else + { + dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData)); + } + + return dp; +} + +bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const +{ + bool result = true; + + try + { + Reference xCntType(mrXMimeCntFactory->createMimeContentType(contentType)); + } + catch( IllegalArgumentException& ) + { + result = false; + } + + return result; +} + +NSArray* DataFlavorMapper::flavorSequenceToTypesArray(const css::uno::Sequence& flavors) const +{ + sal_uInt32 nFlavors = flavors.getLength(); + NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity: 1]; + + bool bNeedDummyInternalFlavor(false); + + for (sal_uInt32 i = 0; i < nFlavors; i++) + { + if( flavors[i].MimeType.startsWith("image/bmp") ) + { + [array addObject: NSPasteboardTypeTIFF]; + } + else + { + const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor); + + if (str != nullptr) + { + [str retain]; + [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 || bNeedDummyInternalFlavor) + { + [array addObject: PBTYPE_DUMMY_INTERNAL]; + } + + return [array autorelease]; +} + +css::uno::Sequence DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const +{ + int nFormats = [types count]; + Sequence 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() +{ + 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]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DataFlavorMapping.hxx b/vcl/osx/DataFlavorMapping.hxx new file mode 100644 index 000000000..4720a7f73 --- /dev/null +++ b/vcl/osx/DataFlavorMapping.hxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DATAFLAVORMAPPING_HXX +#define INCLUDED_VCL_OSX_DATAFLAVORMAPPING_HXX + +#include +#include +#include +#include + +#include +#import +#include + +#include +#include + +/* 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 css::uno::Any getOOoData() = 0; +}; + +typedef std::unique_ptr DataProviderPtr_t; + +class DataFlavorMapper +{ +public: + /* Initialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service + cannot be created. + */ + DataFlavorMapper(); + ~DataFlavorMapper(); + + /* Map a system data flavor to an OpenOffice data flavor. + Return an empty string if there is not suitable + mapping from a system data flavor to an LibreOffice data + flavor. + */ + css::datatransfer::DataFlavor systemToOpenOfficeFlavor( const NSString* systemDataFlavor) const; + + /* Map an OpenOffice data flavor to a system data flavor. + If there is no suitable mapping available NULL will + be returned. + */ + const NSString* openOfficeToSystemFlavor(const css::datatransfer::DataFlavor& oooDataFlavor, bool& rbInternal) const; + + /* Select the best available image data type + If there is no suitable mapping available NULL will + be returned. + */ + static NSString* openOfficeImageToSystemFlavor(NSPasteboard* pPasteboard); + + /* 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( const NSString* systemFlavor, + const css::uno::Reference< css::datatransfer::XTransferable > & rTransferable) const; + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + static DataProviderPtr_t getDataProvider( const NSString* systemFlavor, NSArray* systemData); + + /* Get a data provider which is able to provide 'systemData' in the OOo expected format. + */ + static DataProviderPtr_t getDataProvider( const NSString* systemFlavor, NSData* systemData); + + /* Translate a sequence of DataFlavors into an 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 css::uno::Sequence& flavors) const; + + /* Translate an 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. + */ + css::uno::Sequence typesArrayToFlavorSequence(NSArray* types) const; + + /* Returns an NSArray containing all pasteboard types supported by OOo + */ + static NSArray* getAllSupportedPboardTypes(); + +private: + /* Determines if the provided Mime content type is valid. + */ + bool isValidMimeContentType(const OUString& contentType) const; + +private: + css::uno::Reference< css::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory; + typedef std::unordered_map< OUString, NSString* > OfficeOnlyTypes; + mutable OfficeOnlyTypes maOfficeOnlyTypes; +}; + +typedef std::shared_ptr DataFlavorMapperPtr_t; + +#endif // INCLUDED_VCL_OSX_DATAFLAVORMAPPING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragActionConversion.cxx b/vcl/osx/DragActionConversion.cxx new file mode 100644 index 000000000..3af6cd010 --- /dev/null +++ b/vcl/osx/DragActionConversion.cxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "DragActionConversion.hxx" +#include + +using namespace com::sun::star::datatransfer::dnd; + +/* Convert office drag actions as defined in + css::datatransfer::dnd::DNDConstants + 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 + css::datatransfer::dnd::DNDConstants. + */ +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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragActionConversion.hxx b/vcl/osx/DragActionConversion.hxx new file mode 100644 index 000000000..47e6ebed5 --- /dev/null +++ b/vcl/osx/DragActionConversion.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DRAGACTIONCONVERSION_HXX +#define INCLUDED_VCL_OSX_DRAGACTIONCONVERSION_HXX + +#include + +#include +#import +#include + +/* Convert office drag actions as defined in + css::datatransfer::dnd::DNDConstants + into system conform drag actions. + */ +unsigned int OfficeToSystemDragActions(sal_Int8 dragActions); + +/* Convert system conform drag actions into office conform + drag actions as defined in + css::datatransfer::dnd::DNDConstants. + */ +sal_Int8 SystemToOfficeDragActions(unsigned int dragActions); + +#endif // INCLUDED_VCL_OSX_DRAGACTIONCONVERSION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragSource.cxx b/vcl/osx/DragSource.cxx new file mode 100644 index 000000000..bfe990d73 --- /dev/null +++ b/vcl/osx/DragSource.cxx @@ -0,0 +1,338 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include + +#include + +#include "DragSource.hxx" +#include "DragSourceContext.hxx" +#include "clipboard.hxx" +#include "DragActionConversion.hxx" + +#include + +#include + +using namespace cppu; +using namespace osl; +using namespace com::sun::star; +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; + +// For LibreOffice internal D&D we provide the Transferable without NSDragPboard +// interference as a shortcut, see tdf#100097 for how dbaccess depends on this +uno::Reference DragSource::g_XTransferable; +NSView* DragSource::g_DragSourceView = nil; +bool DragSource::g_DropSuccessSet = false; +bool DragSource::g_DropSuccess = false; + +static OUString dragSource_getImplementationName() +{ + return "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1"; +} + +static Sequence dragSource_getSupportedServiceNames() +{ + return { OUString("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: (BOOL)isLocal +{ + return mDragSource->getSupportedDragOperations(isLocal); +} + +-(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint +{ + (void)anImage; + (void)aPoint; + DragSourceDragEvent dsde(static_cast(mDragSource), + new DragSourceContext, + mDragSource, + DNDConstants::ACTION_COPY, + DNDConstants::ACTION_COPY); + + mDragSource->mXDragSrcListener->dragEnter(dsde); +} + +-(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation +{ + (void)anImage; + (void)aPoint; + // 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(mDragSource), + new DragSourceContext, + static_cast< XDragSource* >(mDragSource), + SystemToOfficeDragActions(operation), + bDropSuccess ); + + mDragSource->mXDragSrcListener->dragDropEnd(dsde); + mDragSource->mXDragSrcListener.clear(); +} + +-(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint +{ + (void)draggedImage; + (void)screenPoint; + DragSourceDragEvent dsde(static_cast(mDragSource), + new DragSourceContext, + mDragSource, + DNDConstants::ACTION_COPY, + DNDConstants::ACTION_COPY); + + mDragSource->mXDragSrcListener->dragOver(dsde); +} + +@end + +DragSource::DragSource(): + WeakComponentImplHelper(m_aMutex), + mView(nullptr), + mpFrame(nullptr), + mLastMouseEventBeforeStartDrag(nil), + mDragSourceHelper(nil), + m_MouseButton(0) +{ +} + +DragSource::~DragSource() +{ + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + [static_cast>(mView) unregisterMouseEventListener: mDragSourceHelper]; + [mDragSourceHelper release]; +} + +void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments) +{ + if (aArguments.getLength() < 2) + { + throw Exception("DragSource::initialize: Not enough parameter.", + static_cast(this)); + } + + Any pNSView = aArguments[1]; + sal_uInt64 tmp = 0; + pNSView >>= tmp; + mView = reinterpret_cast(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 therefore 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("DragSource::initialize: Provided view doesn't support mouse listener", + static_cast(this)); + } + NSWindow* pWin = [mView window]; + if( ! pWin || ![pWin respondsToSelector: @selector(getSalFrame)] ) + { + throw Exception("DragSource::initialize: Provided view is not attached to a vcl frame", + static_cast(this)); + } + mpFrame = reinterpret_cast([pWin performSelector: @selector(getSalFrame)]); + + mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this]; + + if (mDragSourceHelper == nil) + { + throw Exception("DragSource::initialize: Cannot initialize DragSource", + static_cast(this)); + } + + [static_cast>(mView) registerMouseEventListener: mDragSourceHelper]; +} + +sal_Bool SAL_CALL DragSource::isDragImageSupported( ) +{ + return true; +} + +sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ ) +{ + return 0; +} + +void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 /*cursor*/, + sal_Int32 /*image*/, + const uno::Reference& transferable, + const uno::Reference& listener ) +{ + MutexGuard guard(m_aMutex); + + assert(listener.is() && "DragSource::startDrag: No XDragSourceListener provided"); + assert(transferable.is() && "DragSource::startDrag: No transferable provided"); + + trigger.Event >>= mMouseEvent; + m_MouseButton= mMouseEvent.Buttons; + mXDragSrcListener = listener; + mXCurrentContext = static_cast(new DragSourceContext); + rtl::Reference clipb(new AquaClipboard(nullptr, false)); + g_XTransferable = transferable; + clipb->setContents(g_XTransferable, uno::Reference()); + 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; + + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.7 dragImage:at:offset:event:pasteboard:source:slideBack: + [mView dragImage: dragImage + at: p + offset: NSMakeSize(0,0) + event: mLastMouseEventBeforeStartDrag + pasteboard: clipb->getPasteboard() + source: mDragSourceHelper + slideBack: true]; + SAL_WNODEPRECATED_DECLARATIONS_POP + + [dragImage release]; + + g_XTransferable.clear(); + 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; +} + +OUString SAL_CALL DragSource::getImplementationName( ) +{ + return dragSource_getImplementationName(); +} + +sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames() +{ + return dragSource_getSupportedServiceNames(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragSource.hxx b/vcl/osx/DragSource.hxx new file mode 100644 index 000000000..9027ac455 --- /dev/null +++ b/vcl/osx/DragSource.hxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DRAGSOURCE_HXX +#define INCLUDED_VCL_OSX_DRAGSOURCE_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#import +#include + +class DragSource; +class AquaSalFrame; + +/* The functions declared in this protocol are actually + declared in vcl/inc/osx/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:(BOOL)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::WeakComponentImplHelper< css::datatransfer::dnd::XDragSource, + css::lang::XInitialization, + css::lang::XServiceInfo > +{ +public: + DragSource(); + virtual ~DragSource() override; + DragSource(const DragSource&) = delete; + DragSource& operator=(const DragSource&) = delete; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XDragSource + virtual sal_Bool SAL_CALL isDragImageSupported( ) override; + + virtual sal_Int32 SAL_CALL getDefaultCursor(sal_Int8 dragAction) override; + + virtual void SAL_CALL startDrag( const css::datatransfer::dnd::DragGestureEvent& trigger, + sal_Int8 sourceActions, + sal_Int32 cursor, + sal_Int32 image, + const css::uno::Reference< css::datatransfer::XTransferable >& transferable, + const css::uno::Reference< css::datatransfer::dnd::XDragSourceListener >& listener ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + void saveMouseEvent(NSEvent* theEvent); + unsigned int getSupportedDragOperations(bool isLocal) const; + +public: + // The context notifies the XDragSourceListeners + css::uno::Reference< css::datatransfer::dnd::XDragSourceContext > mXCurrentContext; + + id mView; + AquaSalFrame* mpFrame; + NSEvent* mLastMouseEventBeforeStartDrag; + DragSourceHelper* mDragSourceHelper; + css::awt::MouseEvent mMouseEvent; + css::uno::Reference< css::datatransfer::XTransferable > mXTransferable; + css::uno::Reference< css::datatransfer::dnd::XDragSourceListener > mXDragSrcListener; + // The mouse button that set off the drag and drop operation + short m_MouseButton; + sal_Int8 mDragSourceActions; + + static css::uno::Reference< css::datatransfer::XTransferable > g_XTransferable; + static NSView* g_DragSourceView; + static bool g_DropSuccessSet; + static bool g_DropSuccess; + +}; + +#endif // INCLUDED_VCL_OSX_DRAGSOURCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragSourceContext.cxx b/vcl/osx/DragSourceContext.cxx new file mode 100644 index 000000000..253dc867d --- /dev/null +++ b/vcl/osx/DragSourceContext.cxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "DragSourceContext.hxx" + +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() : + WeakComponentImplHelper(m_aMutex) +{ +} + +DragSourceContext::~DragSourceContext() +{ +} + +sal_Int32 SAL_CALL DragSourceContext::getCurrentCursor( ) +{ + return 0; +} + +void SAL_CALL DragSourceContext::setCursor( sal_Int32 /*cursorId*/ ) +{ +} + +void SAL_CALL DragSourceContext::setImage( sal_Int32 /*imageId*/ ) +{ +} + +void SAL_CALL DragSourceContext::transferablesFlavorsChanged( ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DragSourceContext.hxx b/vcl/osx/DragSourceContext.hxx new file mode 100644 index 000000000..3ebeb362b --- /dev/null +++ b/vcl/osx/DragSourceContext.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DRAGSOURCECONTEXT_HXX +#define INCLUDED_VCL_OSX_DRAGSOURCECONTEXT_HXX + +#include +#include +#include + +// 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::WeakComponentImplHelper +{ +public: + DragSourceContext(); + virtual ~DragSourceContext() override; + DragSourceContext(const DragSourceContext&) = delete; + DragSourceContext& operator=(const DragSourceContext&) = delete; + + virtual sal_Int32 SAL_CALL getCurrentCursor( ) override; + + virtual void SAL_CALL setCursor( sal_Int32 cursorId ) override; + + virtual void SAL_CALL setImage( sal_Int32 imageId ) override; + + virtual void SAL_CALL transferablesFlavorsChanged( ) override; +}; + +#endif // INCLUDED_VCL_OSX_DRAGSOURCECONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DropTarget.cxx b/vcl/osx/DropTarget.cxx new file mode 100644 index 000000000..26398cb90 --- /dev/null +++ b/vcl/osx/DropTarget.cxx @@ -0,0 +1,548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include "clipboard.hxx" +#include "DropTarget.hxx" +#include "DragActionConversion.hxx" +#include "DragSource.hxx" +#include +#include +#include +#include +#include +#include +#include + +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 com::sun::star; +using namespace comphelper; + +static OUString dropTarget_getImplementationName() +{ + return "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"; +} + +static Sequence dropTarget_getSupportedServiceNames() +{ + return { OUString("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 + + void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds) + { + rPoint.y = bounds.size.height - rPoint.y; + } +} + +@implementation DropTargetHelper + +-(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt +{ + self = [super init]; + + if (self) + { + mDropTarget = pdt; + } + + return self; +} + +-(NSDragOperation)draggingEntered:(id )sender +{ + return mDropTarget->draggingEntered(sender); +} + +-(NSDragOperation)draggingUpdated:(id )sender +{ + return mDropTarget->draggingUpdated(sender); +} + +-(void)draggingExited:(id )sender +{ + mDropTarget->draggingExited(sender); +} + +-(BOOL)prepareForDragOperation:(id )sender +{ + (void) sender; + return DropTarget::prepareForDragOperation(); +} + +-(BOOL)performDragOperation:(id )sender +{ + (void) sender; + return mDropTarget->performDragOperation(); +} + +-(void)concludeDragOperation:(id )sender +{ + mDropTarget->concludeDragOperation(sender); +} + +@end + +DropTarget::DropTarget() : + WeakComponentImplHelper(m_aMutex), + mView(nil), + mpFrame(nullptr), + 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 = std::make_shared(); +} + +DropTarget::~DropTarget() +{ + if( AquaSalFrame::isAlive( mpFrame ) ) + [static_cast>(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 interested in the drag actions + // supported by the source + if (mDragSourceSupportedActions & mDefaultActions) + { + sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); + + NSRect bounds = [mView bounds]; + NSPoint mouseLoc = [NSEvent mouseLocation]; + + id wnd = [mView window]; + NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast(dragLocation.x); + sal_Int32 posY = static_cast(dragLocation.y); + + NSPasteboard* dragPboard = [sender draggingPasteboard]; + mXCurrentDragClipboard = new AquaClipboard(dragPboard, false); + + uno::Reference xTransferable = DragSource::g_XTransferable.is() ? + DragSource::g_XTransferable : mXCurrentDragClipboard->getContents(); + + DropTargetDragEnterEvent dtdee(static_cast(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 mouseLoc = [NSEvent mouseLocation]; + + id wnd = [mView window]; + NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast(dragLocation.x); + sal_Int32 posY = static_cast(dragLocation.y); + + DropTargetDragEvent dtde(static_cast(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); + } + + if (dragOp == NSDragOperationNone) + [[NSCursor operationNotAllowedCursor] set]; + else if (dragOp == NSDragOperationCopy) + [[NSCursor dragCopyCursor] set]; + else + [[NSCursor arrowCursor] set]; + + return dragOp; +} + +void DropTarget::draggingExited(id /*sender*/) +{ + DropTargetEvent dte(static_cast(this), 0); + fire_dragExit(dte); + mDragSourceSupportedActions = DNDConstants::ACTION_NONE; + mSelectedDropAction = DNDConstants::ACTION_NONE; + [[NSCursor arrowCursor] set]; +} + +BOOL DropTarget::prepareForDragOperation() +{ + return true; +} + +BOOL DropTarget::performDragOperation() +{ + bool bSuccess = false; + + if (mSelectedDropAction != DNDConstants::ACTION_NONE) + { + uno::Reference xTransferable = DragSource::g_XTransferable; + + if (!DragSource::g_XTransferable.is()) + { + xTransferable = mXCurrentDragClipboard->getContents(); + } + + NSRect bounds = [mView bounds]; + NSPoint mouseLoc = [NSEvent mouseLocation]; + + id wnd = [mView window]; + NSPoint dragLocation = [mView convertPoint:[wnd convertRectFromScreen:NSMakeRect(mouseLoc.x, mouseLoc.y, 1, 1)].origin fromView:nil]; + + CocoaToVCL(dragLocation, bounds); + + sal_Int32 posX = static_cast(dragLocation.x); + sal_Int32 posY = static_cast(dragLocation.y); + + DropTargetDropEvent dtde(static_cast(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.clear(); + [[NSCursor arrowCursor] set]; +} + +// 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) +{ + if (aArguments.getLength() < 2) + { + throw RuntimeException("DropTarget::initialize: Cannot install window event handler", + static_cast(this)); + } + + Any pNSView = aArguments[0]; + sal_uInt64 tmp = 0; + pNSView >>= tmp; + mView = reinterpret_cast(tmp); + mpFrame = [static_cast(mView) getSalFrame]; + + mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; + + [static_cast>(mView) registerDraggingDestinationHandler:mDropTargetHelper]; + [mView registerForDraggedTypes: DataFlavorMapper::getAllSupportedPboardTypes()]; + + id wnd = [mView window]; + NSWindow* parentWnd = [wnd parentWindow]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSTitleWindowMask' is deprecated: first deprecated in macOS 10.12 + unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask); +SAL_WNODEPRECATED_DECLARATIONS_POP + unsigned int wndStyles = [wnd styleMask] & topWndStyle; + + if (parentWnd == nil && (wndStyles == topWndStyle)) + { + [wnd registerDraggingDestinationHandler:mDropTargetHelper]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create + // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead" + [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; +SAL_WNODEPRECATED_DECLARATIONS_POP + } +} + +void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference& dtl) +{ + rBHelper.addListener(cppu::UnoType::get(), dtl); +} + +void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference& dtl) +{ + rBHelper.removeListener(cppu::UnoType::get(), dtl); +} + +sal_Bool SAL_CALL DropTarget::isActive( ) +{ + return mbActive; +} + +void SAL_CALL DropTarget::setActive(sal_Bool active) +{ + mbActive = active; +} + +sal_Int8 SAL_CALL DropTarget::getDefaultActions() +{ + return mDefaultActions; +} + +void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) +{ + OSL_ENSURE( actions < 8, "No valid default actions"); + mDefaultActions= actions; +} + +void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) +{ + mSelectedDropAction = dragOperation; +} + +void SAL_CALL DropTarget::rejectDrag() +{ + mSelectedDropAction = DNDConstants::ACTION_NONE; +} + +void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) +{ + mSelectedDropAction = dropOperation; +} + +void SAL_CALL DropTarget::rejectDrop() +{ + mSelectedDropAction = DNDConstants::ACTION_NONE; +} + +void SAL_CALL DropTarget::dropComplete(sal_Bool success) +{ + // Reset the internal transferable used as shortcut in case this is + // an internal D&D operation + DragSource::g_XTransferable.clear(); + DragSource::g_DropSuccessSet = true; + DragSource::g_DropSuccess = success; +} + +void DropTarget::fire_drop( const DropTargetDropEvent& dte) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + uno::Reference listener( static_cast( iter.next())); + + try { listener->drop( dte); } + catch(RuntimeException&) {} + } + } +} + +void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + uno::Reference listener( static_cast( iter.next())); + + try { listener->dragEnter( e); } + catch (RuntimeException&) {} + } + } +} + +void DropTarget::fire_dragExit(const DropTargetEvent& dte) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + uno::Reference listener( static_cast( iter.next())); + + try { listener->dragExit( dte); } + catch (RuntimeException&) {} + } + } +} + +void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer ); + while( iter.hasMoreElements()) + { + uno::Reference listener( static_cast( iter.next())); + + try { listener->dragOver( dtde); } + catch (RuntimeException&) {} + } + } +} + +void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) +{ + OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType::get()); + if( pContainer) + { + OInterfaceIteratorHelper iter( *pContainer); + while( iter.hasMoreElements()) + { + uno::Reference listener( static_cast( iter.next())); + + try { listener->dropActionChanged( dtde); } + catch (RuntimeException&) {} + } + } +} + +OUString SAL_CALL DropTarget::getImplementationName() +{ + return dropTarget_getImplementationName(); +} + +sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) +{ + return dropTarget_getSupportedServiceNames(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/DropTarget.hxx b/vcl/osx/DropTarget.hxx new file mode 100644 index 000000000..aafb64495 --- /dev/null +++ b/vcl/osx/DropTarget.hxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DROPTARGET_HXX +#define INCLUDED_VCL_OSX_DROPTARGET_HXX + +#include "DataFlavorMapping.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#import +#include + +class DropTarget; +class AquaSalFrame; + +/* The functions declared in this protocol are actually + declared in vcl/inc/osx/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 )sender; +-(NSDragOperation)draggingUpdated:(id )sender; +-(void)draggingExited:(id )sender; +-(BOOL)prepareForDragOperation:(id )sender; +-(BOOL)performDragOperation:(id )sender; +-(void)concludeDragOperation:(id )sender; + +@end + +class DropTarget: public cppu::BaseMutex, + public cppu::WeakComponentImplHelper< css::lang::XInitialization, + css::datatransfer::dnd::XDropTarget, + css::datatransfer::dnd::XDropTargetDragContext, + css::datatransfer::dnd::XDropTargetDropContext, + css::lang::XServiceInfo > +{ +public: + DropTarget(); + virtual ~DropTarget() override; + DropTarget(const DropTarget&) = delete; + DropTarget& operator=(const DropTarget&) = delete; + + // Overrides WeakComponentImplHelper::disposing which is called by + // WeakComponentImplHelper::dispose + // Must be called. + virtual void SAL_CALL disposing() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XDropTarget + virtual void SAL_CALL addDropTargetListener( const css::uno::Reference< css::datatransfer::dnd::XDropTargetListener >& dtl ) override; + + virtual void SAL_CALL removeDropTargetListener( const css::uno::Reference< css::datatransfer::dnd::XDropTargetListener >& dtl ) override; + + // Default is not active + virtual sal_Bool SAL_CALL isActive() override; + virtual void SAL_CALL setActive(sal_Bool isActive) override; + virtual sal_Int8 SAL_CALL getDefaultActions() override; + virtual void SAL_CALL setDefaultActions(sal_Int8 actions) override; + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrag(sal_Int8 dragOperation) override; + virtual void SAL_CALL rejectDrag() override; + + // XDropTargetDragContext + virtual void SAL_CALL acceptDrop(sal_Int8 dropOperation) override; + virtual void SAL_CALL rejectDrop() override; + virtual void SAL_CALL dropComplete(sal_Bool success) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // NSDraggingDestination protocol functions + NSDragOperation draggingEntered(id sender); + NSDragOperation draggingUpdated(id sender); + void draggingExited(id sender); + static BOOL prepareForDragOperation(); + BOOL performDragOperation(); + 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 css::datatransfer::dnd::DropTargetDropEvent& dte); + void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtdee); + void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte); + void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEvent& dtde); + void fire_dropActionChanged(const css::datatransfer::dnd::DropTargetDragEvent& dtde); + +private: + css::uno::Reference< css::datatransfer::dnd::XDropTargetDragContext > mXCurrentDragContext; + css::uno::Reference< css::datatransfer::dnd::XDropTargetDropContext > mXCurrentDropContext; + css::uno::Reference< css::datatransfer::clipboard::XClipboard > mXCurrentDragClipboard; + DataFlavorMapperPtr_t mDataFlavorMapper; + id mView; + AquaSalFrame* mpFrame; + DropTargetHelper* mDropTargetHelper; + bool mbActive; + sal_Int8 mDragSourceSupportedActions; + sal_Int8 mSelectedDropAction; + sal_Int8 mDefaultActions; +}; + +#endif // INCLUDED_VCL_OSX_DROPTARGET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/HtmlFmtFlt.cxx b/vcl/osx/HtmlFmtFlt.cxx new file mode 100644 index 000000000..940bf90cb --- /dev/null +++ b/vcl/osx/HtmlFmtFlt.cxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "HtmlFmtFlt.hxx" + +#include +#include + +#include +#include +#include +#include +#include + +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. Starting 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 +// and (no space between !-- and the +// text + +namespace +{ +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(); +} + +} + +// the office always writes the start and end html tag in upper cases and +// without spaces both tags don't allow parameters +const std::string TAG_HTML(""); +const std::string TAG_END_HTML(""); + +// The body tag may have parameters so we need to search for the +// closing '>' manually e.g. #92840# +const std::string TAG_BODY(" TextHtmlToHTMLFormat(Sequence const & aTextHtml) +{ + OSL_ASSERT(aTextHtml.getLength() > 0); + + if (aTextHtml.getLength() <= 0) + return Sequence(); + + // 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(aTextHtml.getConstArray()), + reinterpret_cast(aTextHtml.getConstArray()) + aTextHtml.getLength()); + + std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader - 1; // we start one before '' 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 ? + + // The body tag may have parameters so we need to search for the + // closing '>' manually e.g. #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 byteSequence(htmlFormat.length() + 1); // space the trailing '\0' + memset(byteSequence.getArray(), 0, byteSequence.getLength()); + + memcpy( + static_cast(byteSequence.getArray()), + static_cast(htmlFormat.c_str()), + htmlFormat.length()); + + return byteSequence; +} + +const char* const HtmlStartTag = " HTMLFormatToTextHtml(const Sequence& aHTMLFormat) +{ + assert(isHTMLFormat(aHTMLFormat) && "No HTML Format provided"); + + Sequence& nonconstHTMLFormatRef = const_cast< Sequence& >(aHTMLFormat); + char* dataStart = reinterpret_cast(nonconstHTMLFormatRef.getArray()); + char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1; + const char* htmlStartTag = strcasestr(dataStart, HtmlStartTag); + + 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 == nullptr) + { + return aHTMLFormat; + } + + sal_Int32 len = dataEnd - htmlStartTag; + Sequence plainHtmlData(len); + + memcpy(static_cast(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 const HtmlFormatStartLen = sizeof(HtmlFormatStart) - 1; + +bool isHTMLFormat(const Sequence& aHtmlSequence) +{ + if (aHtmlSequence.getLength() < HtmlFormatStartLen) + return false; + + return rtl_str_compareIgnoreAsciiCase_WithLength(HtmlFormatStart, + HtmlFormatStartLen, + reinterpret_cast(aHtmlSequence.getConstArray()), + HtmlFormatStartLen) == 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/HtmlFmtFlt.hxx b/vcl/osx/HtmlFmtFlt.hxx new file mode 100644 index 000000000..a50b72a6b --- /dev/null +++ b/vcl/osx/HtmlFmtFlt.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_HTMLFMTFLT_HXX +#define INCLUDED_VCL_OSX_HTMLFMTFLT_HXX + +#include + +/* Transform plain HTML into the format expected by MS Office. + */ +css::uno::Sequence TextHtmlToHTMLFormat(css::uno::Sequence const& aTextHtml); + +/* Transform the MS Office HTML format into plain HTML. + */ +css::uno::Sequence HTMLFormatToTextHtml(const css::uno::Sequence& 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 css::uno::Sequence& aHtmlSequence); + +#endif // INCLUDED_VCL_OSX_HTMLFMTFLT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/OSXTransferable.cxx b/vcl/osx/OSXTransferable.cxx new file mode 100644 index 000000000..77417f3c2 --- /dev/null +++ b/vcl/osx/OSXTransferable.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include "OSXTransferable.hxx" + +#include "DataFlavorMapping.hxx" + +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::lang; + +namespace +{ + bool isValidFlavor( const DataFlavor& aFlavor ) + { + size_t len = aFlavor.MimeType.getLength(); + Type dtype = aFlavor.DataType; + return ((len > 0) && ((dtype == cppu::UnoType>::get()) || (dtype == cppu::UnoType::get()))); + } + +bool cmpAllContentTypeParameter(const Reference & xLhs, + const Reference & xRhs) +{ + Sequence xLhsFlavors = xLhs->getParameters(); + Sequence 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; +} + +} // unnamed namespace + +OSXTransferable::OSXTransferable(const Reference & 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 ) +{ + if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor)) + { + throw UnsupportedFlavorException("AquaClipboard: Unsupported data flavor", + static_cast(this)); + } + + bool bInternal(false); + NSString const * sysFormat = + (aFlavor.MimeType.startsWith("image/png")) + ? DataFlavorMapper::openOfficeImageToSystemFlavor( mPasteboard ) + : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor, bInternal); + DataProviderPtr_t dp; + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create multiple + // pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead" + if ([sysFormat caseInsensitiveCompare: NSFilenamesPboardType] == NSOrderedSame) +SAL_WNODEPRECATED_DECLARATIONS_POP + { + NSArray* sysData = [mPasteboard propertyListForType: const_cast(sysFormat)]; + dp = DataFlavorMapper::getDataProvider(sysFormat, sysData); + } + else + { + NSData* sysData = [mPasteboard dataForType: const_cast(sysFormat)]; + dp = DataFlavorMapper::getDataProvider(sysFormat, sysData); + } + + if (dp.get() == nullptr) + { + throw UnsupportedFlavorException("AquaClipboard: Unsupported data flavor", + static_cast(this)); + } + + return dp->getOOoData(); +} + +Sequence< DataFlavor > SAL_CALL OSXTransferable::getTransferDataFlavors( ) +{ + return mFlavorList; +} + +sal_Bool SAL_CALL OSXTransferable::isDataFlavorSupported(const DataFlavor& aFlavor) +{ + for (const DataFlavor& rFlavor : mFlavorList) + if (compareDataFlavors(aFlavor, rFlavor)) + return true; + + return false; +} + +void OSXTransferable::initClipboardItemList() +{ + NSArray* pboardFormats = [mPasteboard types]; + + if (pboardFormats == nullptr) + { + throw RuntimeException("AquaClipboard: Cannot get clipboard data", + static_cast(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 xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType)); + Reference xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType)); + + if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType()) || + !cmpAllContentTypeParameter(xLhs, xRhs)) + { + return false; + } + } + catch( IllegalArgumentException& ) + { + OSL_FAIL( "Invalid content type detected" ); + return false; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/OSXTransferable.hxx b/vcl/osx/OSXTransferable.hxx new file mode 100644 index 000000000..2e7056145 --- /dev/null +++ b/vcl/osx/OSXTransferable.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_OSXTRANSFERABLE_HXX +#define INCLUDED_VCL_OSX_OSXTRANSFERABLE_HXX + +#include +#include +#include +#include + +#include "DataFlavorMapping.hxx" + +#include +#import +#include + +#include +#include + +class OSXTransferable : public ::cppu::WeakImplHelper +{ +public: + explicit OSXTransferable(css::uno::Reference< css::datatransfer::XMimeContentTypeFactory> const & rXMimeCntFactory, + DataFlavorMapperPtr_t pDataFlavorMapper, + NSPasteboard* pasteboard); + + virtual ~OSXTransferable() override; + OSXTransferable(const OSXTransferable&) = delete; + OSXTransferable& operator=(const OSXTransferable&) = delete; + + // XTransferable + + virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& aFlavor ) override; + + virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) override; + + virtual sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& aFlavor ) override; + + // Helper functions not part of the XTransferable interface + + void initClipboardItemList(); + + //css::uno::Any getClipboardItemData(ClipboardItemPtr_t clipboardItem); + + bool compareDataFlavors( const css::datatransfer::DataFlavor& lhs, + const css::datatransfer::DataFlavor& rhs ); + +private: + css::uno::Sequence< css::datatransfer::DataFlavor > mFlavorList; + css::uno::Reference< css::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory; + DataFlavorMapperPtr_t mDataFlavorMapper; + NSPasteboard* mPasteboard; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/PictToBmpFlt.cxx b/vcl/osx/PictToBmpFlt.cxx new file mode 100644 index 000000000..a818cb5e7 --- /dev/null +++ b/vcl/osx/PictToBmpFlt.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include + +#include "PictToBmpFlt.hxx" + +bool ImageToPNG( css::uno::Sequence const & rImgData, + css::uno::Sequence& rPngData) +{ + NSData* pData = [NSData dataWithBytesNoCopy: const_cast(rImgData.getConstArray()) length: rImgData.getLength() freeWhenDone: false]; + if( !pData) + return false; + + NSBitmapImageRep* pRep =[NSBitmapImageRep imageRepWithData: pData]; + if( !pRep) + return false; + + NSData* pOut = [pRep representationUsingType: NSBitmapImageFileTypePNG properties: @{ }]; + if( !pOut) + return false; + + const size_t nPngSize = [pOut length]; + rPngData.realloc( nPngSize); + [pOut getBytes: rPngData.getArray() length: nPngSize]; + return (nPngSize > 0); +} + +bool PNGToImage( css::uno::Sequence const & rPngData, + css::uno::Sequence& rImgData, + NSBitmapImageFileType eOutFormat + ) +{ + NSData* pData = [NSData dataWithBytesNoCopy: const_cast(rPngData.getConstArray()) length: rPngData.getLength() freeWhenDone: false]; + if( !pData) + return false; + + NSBitmapImageRep* pRep = [NSBitmapImageRep imageRepWithData: pData]; + if( !pRep) + return false; + + NSData* pOut = [pRep representationUsingType: eOutFormat properties: @{ }]; + if( !pOut) + return false; + + const size_t nImgSize = [pOut length]; + rImgData.realloc( nImgSize); + [pOut getBytes: rImgData.getArray() length: nImgSize]; + return (nImgSize > 0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/PictToBmpFlt.hxx b/vcl/osx/PictToBmpFlt.hxx new file mode 100644 index 000000000..027bd178b --- /dev/null +++ b/vcl/osx/PictToBmpFlt.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_PICTTOBMPFLT_HXX +#define INCLUDED_VCL_OSX_PICTTOBMPFLT_HXX + +#include + +#include +#include +#include + +bool ImageToPNG( css::uno::Sequence const & rImgData, + css::uno::Sequence& rPngData); + +bool PNGToImage( css::uno::Sequence const & rPngData, + css::uno::Sequence& rImgData, + NSBitmapImageFileType eOutFormat); + +#endif // INCLUDED_VCL_OSX_PICTTOBMPFLT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/README.a11y b/vcl/osx/README.a11y new file mode 100644 index 000000000..4422713bc --- /dev/null +++ b/vcl/osx/README.a11y @@ -0,0 +1,7 @@ +Naming scheme: + +a11yXYZhelper: Helper class providing static methods + +a11yXYZwrapper: Wrapper around one (or two) UNO-interfaces + +a11ywrapperXYZ: Subclass of a11ywrapper for a specific AXRole diff --git a/vcl/osx/a11yactionwrapper.h b/vcl/osx/a11yactionwrapper.h new file mode 100644 index 000000000..20b2bad1b --- /dev/null +++ b/vcl/osx/a11yactionwrapper.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YACTIONWRAPPER_H +#define INCLUDED_VCL_OSX_A11YACTIONWRAPPER_H + +#include +#include + +@interface AquaA11yActionWrapper : NSObject +{ +} ++(NSArray *)actionNamesForElement:(AquaA11yWrapper *)wrapper; ++(void)doAction:(NSString *)action ofElement:(AquaA11yWrapper *)wrapper; +@end + +#endif // INCLUDED_VCL_OSX_A11YACTIONWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yactionwrapper.mm b/vcl/osx/a11yactionwrapper.mm new file mode 100644 index 000000000..8af087edf --- /dev/null +++ b/vcl/osx/a11yactionwrapper.mm @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include + +#include "a11yactionwrapper.h" + +// Wrapper for XAccessibleAction + +@implementation AquaA11yActionWrapper : NSObject + ++(NSString *)nativeActionNameFor:(NSString *)actionName { + // TODO: Optimize ? + // Use NSAccessibilityActionDescription + if ( [ actionName isEqualToString: @"press" ] ) { + 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 ] ) { + 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 ] ) { + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ycomponentwrapper.h b/vcl/osx/a11ycomponentwrapper.h new file mode 100644 index 000000000..92c6b1b49 --- /dev/null +++ b/vcl/osx/a11ycomponentwrapper.h @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YCOMPONENTWRAPPER_H +#define INCLUDED_VCL_OSX_A11YCOMPONENTWRAPPER_H + +#include +#include + +@interface AquaA11yComponentWrapper : NSObject +{ +} ++(id)sizeAttributeForElement:(AquaA11yWrapper *)wrapper; ++(id)positionAttributeForElement:(AquaA11yWrapper *)wrapper; ++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper; ++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames; ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper; ++(void)setFocusedAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value; +@end + +#endif // INCLUDED_VCL_OSX_A11YCOMPONENTWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ycomponentwrapper.mm b/vcl/osx/a11ycomponentwrapper.mm new file mode 100644 index 000000000..d9d6db175 --- /dev/null +++ b/vcl/osx/a11ycomponentwrapper.mm @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "a11ycomponentwrapper.h" +#include "a11yrolehelper.h" +#include + +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 ( static_cast(size.Width), static_cast(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 ( static_cast(location.X), static_cast( screenRect.size.height - size.Height - location.Y ) ); + return [ NSValue valueWithPoint: nsPoint ]; +} + ++(id)descriptionAttributeForElement:(AquaA11yWrapper *)wrapper { + if ( [ wrapper accessibleExtendedComponent ] ) { + 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 ]; +} + ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper { + bool isSettable = false; + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + if ( [ attribute isEqualToString: NSAccessibilityFocusedAttribute ] + && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityScrollBarRole ] + && ! [ [ AquaA11yRoleHelper getNativeRoleFrom: [ wrapper accessibleContext ] ] isEqualToString: NSAccessibilityStaticTextRole ] ) { + isSettable = true; + } + [ 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( rxParent -> getAccessibleContext(), UNO_QUERY ); + if ( rxComponent.is() ) { + rxComponent -> grabFocus(); + } + } + } + } else { + [ wrapper accessibleComponent ] -> grabFocus(); + } + } +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yfactory.mm b/vcl/osx/a11yfactory.mm new file mode 100644 index 000000000..0a17f15da --- /dev/null +++ b/vcl/osx/a11yfactory.mm @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include + +#include "a11yfocuslistener.hxx" +#include "a11yrolehelper.h" +#include "a11ywrapperbutton.h" +#include "a11ywrapperstatictext.h" +#include "a11ywrappertextarea.h" +#include "a11ywrappercheckbox.h" +#include "a11ywrappercombobox.h" +#include "a11ywrappergroup.h" +#include "a11ywrapperlist.h" +#include "a11ywrapperradiobutton.h" +#include "a11ywrapperradiogroup.h" +#include "a11ywrapperrow.h" +#include "a11ywrapperscrollarea.h" +#include "a11ywrapperscrollbar.h" +#include "a11ywrappersplitter.h" +#include "a11ywrappertabgroup.h" +#include "a11ywrappertoolbar.h" +#include "a11ytablewrapper.h" + +#include + +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() ); + TheAquaA11yFocusTracker::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:(BOOL) bCreate { + return [ AquaA11yFactory wrapperForAccessibleContext: rxAccessibleContext createIfNotExists: bCreate asRadioGroup: NO ]; +} + ++(AquaA11yWrapper *)wrapperForAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext createIfNotExists:(BOOL) bCreate asRadioGroup:(BOOL) asRadioGroup{ + NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ]; + NSValue * nKey = nil; + if ( asRadioGroup ) { + nKey = [ AquaA11yFactory keyForAccessibleContextAsRadioGroup: rxAccessibleContext ]; + } else { + nKey = [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ]; + } + AquaA11yWrapper * aWrapper = static_cast([ 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 and finally all the transients are released. + */ + if ( ! rxAccessibleContext -> getAccessibleStateSet() -> contains ( AccessibleStateType::TRANSIENT ) ) + #endif + { + [ dAllWrapper setObject: aWrapper forKey: nKey ]; + /* fdo#67410: Accessibility notifications are not delivered on NSView subclasses that do not + "reasonably" participate in NSView hierarchy (perhaps the only important point is + that the view is a transitive subview of the NSWindow's content view, but I + did not try to verify that). + + So let the superview-subviews relationship mirror the AXParent-AXChildren relationship. + */ + id parent = [aWrapper accessibilityAttributeValue:NSAccessibilityParentAttribute]; + if (parent) { + if ([parent isKindOfClass:[NSView class]]) { + // SAL_DEBUG("Wrapper INIT: " << [[aWrapper description] UTF8String] << " ==> " << [[parent description] UTF8String]); + NSView *parentView = static_cast(parent); + [parentView addSubview:aWrapper positioned:NSWindowBelow relativeTo:nil]; + } else if ([parent isKindOfClass:NSClassFromString(@"SalFrameWindow")]) { + NSWindow *window = static_cast(parent); + NSView *salView = [window contentView]; + // SAL_DEBUG("Wrapper INIT SAL: " << [[aWrapper description] UTF8String] << " ==> " << [[salView description] UTF8String]); + [salView addSubview:aWrapper positioned:NSWindowBelow relativeTo:nil]; + } else { + // SAL_DEBUG("Wrapper INIT: !! " << [[aWrapper description] UTF8String] << " !==>! " << [[parent description] UTF8String] << "!!"); + } + } else { + // SAL_DEBUG("Wrapper INIT: " << [[aWrapper description] UTF8String] << " ==> NO PARENT"); + } + } + } + return aWrapper; +} + ++(void)insertIntoWrapperRepository: (NSView *) viewElement forAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext { + NSMutableDictionary * dAllWrapper = [ AquaA11yFactory allWrapper ]; + [ dAllWrapper setObject: viewElement forKey: [ AquaA11yFactory keyForAccessibleContext: rxAccessibleContext ] ]; +} + ++(void)removeFromWrapperRepositoryFor: (css::uno::Reference < css::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 ) { + if (![theWrapper isKindOfClass:NSClassFromString(@"SalFrameView")]) { + [theWrapper removeFromSuperview]; + } + [ [ 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 + [ static_cast(theView) accessibleContext ]; + } +} + ++(void)revokeView: (NSView *) theView { + if ( enabled && [ theView isKindOfClass: [ AquaA11yWrapper class ] ] ) { + [ AquaA11yFactory removeFromWrapperRepositoryFor: [ static_cast(theView) accessibleContext ] ]; + } +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yfocuslistener.cxx b/vcl/osx/a11yfocuslistener.cxx new file mode 100644 index 000000000..68eb45a31 --- /dev/null +++ b/vcl/osx/a11yfocuslistener.cxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "a11yfocuslistener.hxx" + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; + +rtl::Reference< AquaA11yFocusListener > AquaA11yFocusListener::theListener; + +rtl::Reference< AquaA11yFocusListener > const & 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( TheAquaA11yFocusTracker::get().getFocusedObject() ); + try { + if( xAccessible.is() ) { + Reference< XAccessibleContext > xContext(xAccessible->getAccessibleContext()); + if( xContext.is() ) + m_focusedObject = [ AquaA11yFactory wrapperForAccessibleContext: xContext ]; + } + } catch(const RuntimeException &) { + // intentionally do nothing .. + } + } + + return m_focusedObject; +} + +void +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(const RuntimeException &) { + // intentionally do nothing .. + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yfocuslistener.hxx b/vcl/osx/a11yfocuslistener.hxx new file mode 100644 index 000000000..44a25cce0 --- /dev/null +++ b/vcl/osx/a11yfocuslistener.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YFOCUSLISTENER_HXX +#define INCLUDED_VCL_OSX_A11YFOCUSLISTENER_HXX + +#include +#include + +class AquaA11yFocusListener : public KeyboardFocusListener +{ + id m_focusedObject; + + static rtl::Reference< AquaA11yFocusListener > theListener; + + AquaA11yFocusListener(); + virtual ~AquaA11yFocusListener() override {}; +public: + + static rtl::Reference< AquaA11yFocusListener > const & get(); + + id getFocusedUIElement(); + + // KeyboardFocusListener + virtual void focusedObjectChanged(const css::uno::Reference< css::accessibility::XAccessible >& xAccessible) override; +}; + +#endif // INCLUDED_VCL_OSX_A11YFOCUSLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yfocustracker.cxx b/vcl/osx/a11yfocustracker.cxx new file mode 100644 index 000000000..057169a30 --- /dev/null +++ b/vcl/osx/a11yfocustracker.cxx @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include + +#include "documentfocuslistener.hxx" + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; + +static vcl::Window * +getWindow(const ::VclSimpleEvent *pEvent) +{ + return static_cast< const ::VclWindowEvent *> (pEvent)->GetWindow(); +} + +// callback function for Application::addEventListener + +void AquaA11yFocusTracker::WindowEventHandler(void * pThis, VclSimpleEvent& rEvent) +{ + AquaA11yFocusTracker *pFocusTracker = static_cast( + pThis); + switch (rEvent.GetId()) + { + case VclEventId::WindowPaint: + pFocusTracker-> toolbox_open_floater( getWindow(&rEvent) ); + break; + case VclEventId::WindowGetFocus: + pFocusTracker->window_got_focus( getWindow(&rEvent) ); + break; + case VclEventId::ObjectDying: + pFocusTracker->m_aDocumentWindowList.erase( getWindow(&rEvent) ); + [[fallthrough]]; + case VclEventId::ToolboxHighlightOff: + pFocusTracker->toolbox_highlight_off( getWindow(&rEvent) ); + break; + case VclEventId::ToolboxHighlight: + pFocusTracker->toolbox_highlight_on( getWindow(&rEvent) ); + break; + case VclEventId::TabpageActivate: + pFocusTracker->tabpage_activated( getWindow(&rEvent) ); + break; + case VclEventId::MenuHighlight: + // Inspired by code in WindowEventHandler in + // vcl/unx/gtk/a11y/atkutil.cxx, find out what kind of event + // it is to avoid blindly using a static_cast and crash, + // fdo#47275. + if( const VclMenuEvent* pMenuEvent = dynamic_cast < const VclMenuEvent* > (&rEvent) ) + { + pFocusTracker->menu_highlighted( pMenuEvent ); + } + else if( const VclAccessibleEvent* pAccEvent = dynamic_cast < const VclAccessibleEvent* > (&rEvent) ) + { + Reference< XAccessible > xAccessible = pAccEvent->GetAccessible(); + if( xAccessible.is() ) + pFocusTracker->setFocusedObject( xAccessible ); + } + break; + default: + break; + } +} + +AquaA11yFocusTracker::AquaA11yFocusTracker() : + m_aWindowEventLink(this, WindowEventHandler), + m_xDocumentFocusListener(new DocumentFocusListener(*this)) +{ + Application::AddEventListener(m_aWindowEventLink); + window_got_focus(Application::GetFocusWindow()); +} + +AquaA11yFocusTracker::~AquaA11yFocusTracker() {} + +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() ) + { + ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() ); + if( nPos != ToolBox::ITEM_NOTFOUND ) + setFocusedObject( xContext->getAccessibleChild( nPos ) ); + //TODO: ToolBox::ImplToolItems::size_type -> sal_Int32! + } + } +} + +void AquaA11yFocusTracker::toolbox_open_floater(vcl::Window *pWindow) +{ + bool bToolboxFound = false; + bool bFloatingWindowFound = false; + vcl::Window * pFloatingWindow = nullptr; + while ( pWindow != nullptr ) { + if ( pWindow->GetType() == WindowType::TOOLBOX ) { + bToolboxFound = true; + } else if ( pWindow->GetType() == WindowType::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(vcl::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 (pWindow)); +} + +void AquaA11yFocusTracker::toolbox_highlight_off(vcl::Window const *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(vcl::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(vcl::Window *pWindow) +{ + // The menu bar is handled through VclEventId::MenuHighlightED + if( ! pWindow || !pWindow->IsReallyVisible() || pWindow->GetType() == WindowType::MENUBARWINDOW ) + return; + + // ToolBoxes are handled through VclEventId::ToolboxHighlight + if( pWindow->GetType() == WindowType::TOOLBOX ) + return; + + if( pWindow->GetType() == WindowType::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() != WindowType::TREELISTBOX) ) + { + setFocusedObject( xAccessible ); + } + else + { + if( m_aDocumentWindowList.insert(pWindow).second ) + m_xDocumentFocusListener->attachRecursive(xAccessible, xContext, xStateSet); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ylistener.cxx b/vcl/osx/a11ylistener.cxx new file mode 100644 index 000000000..b8220c07d --- /dev/null +++ b/vcl/osx/a11ylistener.cxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include "a11ytextwrapper.h" + +#include +#include +#include +#include + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +static 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& ) +{ + [ AquaA11yFactory removeFromWrapperRepositoryFor: [ static_cast(m_wrapperObject) accessibleContext ] ]; +} + +void SAL_CALL +AquaA11yEventListener::notifyEvent( const AccessibleEventObject& aEvent ) +{ + NSString * notification = nil; + id element = m_wrapperObject; + ::css::awt::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 ) + TheAquaA11yFocusTracker::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: deprecate 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); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yrolehelper.h b/vcl/osx/a11yrolehelper.h new file mode 100644 index 000000000..7a4df6dbe --- /dev/null +++ b/vcl/osx/a11yrolehelper.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YROLEHELPER_H +#define INCLUDED_VCL_OSX_A11YROLEHELPER_H + +#include + +@interface AquaA11yRoleHelper : NSObject +{ +} ++(id)getNativeRoleFrom: (css::accessibility::XAccessibleContext *) accessibleContext; ++(id)getNativeSubroleFrom: (sal_Int16) nRole; ++(id)getRoleDescriptionFrom: (NSString *) role with: (NSString *) subRole; +@end + +#endif // INCLUDED_VCL_OSX_A11YROLEHELPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yrolehelper.mm b/vcl/osx/a11yrolehelper.mm new file mode 100644 index 000000000..e42b2d53d --- /dev/null +++ b/vcl/osx/a11yrolehelper.mm @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11yrolehelper.h" + +#include +#include + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; + +@implementation AquaA11yRoleHelper + ++(id)simpleMapNativeRoleFrom: (XAccessibleContext *) accessibleContext { + id nativeRole = nil; + + if (accessibleContext == nullptr) + return nativeRole; + + 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, NSAccessibilityGroupRole ); // 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, NSAccessibilityGroupRole ); // FIXME + MAP( AccessibleRole::HEADING, NSAccessibilityTextAreaRole ); // 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, NSAccessibilitySplitGroupRole ); + 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 ); + + MAP( AccessibleRole::DOCUMENT_PRESENTATION, NSAccessibilityGroupRole ); + MAP( AccessibleRole::DOCUMENT_SPREADSHEET, NSAccessibilityGroupRole ); + MAP( AccessibleRole::DOCUMENT_TEXT, NSAccessibilityGroupRole ); + MAP( AccessibleRole::STATIC, NSAccessibilityStaticTextRole ); + +#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 = static_cast([ 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, @"" ); + + MAP( AccessibleRole::DOCUMENT_PRESENTATION, @"" ); + MAP( AccessibleRole::DOCUMENT_SPREADSHEET, @"" ); + MAP( AccessibleRole::DOCUMENT_TEXT, @"" ); + + MAP( AccessibleRole::STATIC, @"" ); + +#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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yselectionwrapper.h b/vcl/osx/a11yselectionwrapper.h new file mode 100644 index 000000000..923737b65 --- /dev/null +++ b/vcl/osx/a11yselectionwrapper.h @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YSELECTIONWRAPPER_H +#define INCLUDED_VCL_OSX_A11YSELECTIONWRAPPER_H + +#include +#include + +@interface AquaA11ySelectionWrapper : NSObject +{ +} ++(id)selectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper; ++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames; ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper; ++(void)setSelectedChildrenAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value; +@end + +#endif // INCLUDED_VCL_OSX_A11YSELECTIONWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yselectionwrapper.mm b/vcl/osx/a11yselectionwrapper.mm new file mode 100644 index 000000000..163fe27da --- /dev/null +++ b/vcl/osx/a11yselectionwrapper.mm @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include + +#include "a11yselectionwrapper.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 ]; + if( xAccessibleSelection.is() ) + { + 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&) + { + } + } + + return nil; +} + + ++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames +{ + [ attributeNames addObject: NSAccessibilitySelectedChildrenAttribute ]; +} + ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper +{ + (void)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&) { + } +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytablewrapper.h b/vcl/osx/a11ytablewrapper.h new file mode 100644 index 000000000..450a829c1 --- /dev/null +++ b/vcl/osx/a11ytablewrapper.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YTABLEWRAPPER_H +#define INCLUDED_VCL_OSX_A11YTABLEWRAPPER_H + +#include + +#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 // INCLUDED_VCL_OSX_A11YTABLEWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytablewrapper.mm b/vcl/osx/a11ytablewrapper.mm new file mode 100644 index 000000000..e7cd02fce --- /dev/null +++ b/vcl/osx/a11ytablewrapper.mm @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ytablewrapper.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 &) + { + } + [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 + { + 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 &) + { + 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 &) + { + pResult = nil; + } + [ cells autorelease ]; + } + } + + return pResult; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytextattributeswrapper.h b/vcl/osx/a11ytextattributeswrapper.h new file mode 100644 index 000000000..4170f5f8a --- /dev/null +++ b/vcl/osx/a11ytextattributeswrapper.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YTEXTATTRIBUTESWRAPPER_H +#define INCLUDED_VCL_OSX_A11YTEXTATTRIBUTESWRAPPER_H + +#include + +@interface AquaA11yTextAttributesWrapper : NSObject +{ +} ++(NSMutableAttributedString *)createAttributedStringForElement:(AquaA11yWrapper *)wrapper inOrigRange:(id)origRange; +@end +#endif // INCLUDED_VCL_OSX_A11YTEXTATTRIBUTESWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytextattributeswrapper.mm b/vcl/osx/a11ytextattributeswrapper.mm new file mode 100644 index 000000000..433906d7d --- /dev/null +++ b/vcl/osx/a11ytextattributeswrapper.mm @@ -0,0 +1,361 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include + +#include "a11ytextattributeswrapper.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace css_awt = ::com::sun::star::awt; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +// cannot use NSFontDescriptor as it has no notion of explicit NSUn{bold,italic}FontMask +@interface AquaA11yFontDescriptor : NSObject +{ + NSString *_name; + NSFontTraitMask _traits; + CGFloat _size; +} +-(void)setName:(NSString*)name; +-(void)setBold:(NSFontTraitMask)bold; +-(void)setItalic:(NSFontTraitMask)italic; +-(void)setSize:(CGFloat)size; +-(NSFont*)font; +@end + +@implementation AquaA11yFontDescriptor +- (id)init +{ + if((self = [super init])) + { + _name = nil; + _traits = 0; + _size = 0.0; + } + return self; +} + +- (id)initWithDescriptor:(AquaA11yFontDescriptor*)descriptor { + if((self = [super init])) + { + _name = [descriptor->_name retain]; + _traits = descriptor->_traits; + _size = descriptor->_size; + } + return self; +} + +- (void)dealloc { + [_name release]; + [super dealloc]; +} + +-(void)setName:(NSString*)name { + if (_name != name) { + [name retain]; + [_name release]; + _name = name; + } +} + +-(void)setBold:(NSFontTraitMask)bold { + _traits &= ~(NSBoldFontMask | NSUnboldFontMask); + _traits |= bold & (NSBoldFontMask | NSUnboldFontMask); +}; + +-(void)setItalic:(NSFontTraitMask)italic { + _traits &= ~(NSItalicFontMask | NSUnitalicFontMask); + _traits |= italic & (NSItalicFontMask | NSUnitalicFontMask); +}; + +-(void)setSize:(CGFloat)size { _size = size; } + +-(NSFont*)font { + return [[NSFontManager sharedFontManager] fontWithFamily:_name traits:_traits weight:0 size:_size]; +} +@end + +@implementation AquaA11yTextAttributesWrapper : NSObject + ++(int)convertUnderlineStyle:(PropertyValue)property { + int underlineStyle = NSUnderlineStyleNone; + sal_Int16 value = 0; + property.Value >>= value; + if ( value != ::css_awt::FontUnderline::NONE + && value != ::css_awt::FontUnderline::DONTKNOW) { + underlineStyle = NSUnderlineStyleSingle; + } + return underlineStyle; +} + ++(int)convertBoldStyle:(PropertyValue)property { + int boldStyle = NSUnboldFontMask; + float value = 0; + property.Value >>= value; + if ( value == ::css_awt::FontWeight::SEMIBOLD + || value == ::css_awt::FontWeight::BOLD + || value == ::css_awt::FontWeight::ULTRABOLD + || value == ::css_awt::FontWeight::BLACK ) { + boldStyle = NSBoldFontMask; + } + return boldStyle; +} + ++(int)convertItalicStyle:(PropertyValue)property { + int italicStyle = NSUnitalicFontMask; + ::css_awt::FontSlant value = property.Value.get< ::css_awt::FontSlant>(); + if ( value == ::css_awt::FontSlant_ITALIC ) { + italicStyle = NSItalicFontMask; + } + return italicStyle; +} + ++(BOOL)isStrikethrough:(PropertyValue)property { + bool strikethrough = false; + sal_Int16 value = 0; + property.Value >>= value; + if ( value != ::css_awt::FontStrikeout::NONE + && value != ::css_awt::FontStrikeout::DONTKNOW ) { + strikethrough = true; + } + return strikethrough; +} + ++(BOOL)convertBoolean:(PropertyValue)property { + bool myBoolean = false; + bool value = false; + property.Value >>= value; + if ( value ) { + myBoolean = true; + } + return myBoolean; +} + ++(NSNumber *)convertShort:(PropertyValue)property { + sal_Int16 value = 0; + property.Value >>= value; + return [ NSNumber numberWithShort: value ]; +} + ++(void)addColor:(Color)nColor forAttribute:(NSString *)attribute andRange:(NSRange)range toString:(NSMutableAttributedString *)string { + if( nColor == COL_TRANSPARENT ) + return; + const RGBAColor aRGBAColor( nColor); + CGColorRef aColorRef = CGColorCreate ( CGColorSpaceCreateWithName ( kCGColorSpaceGenericRGB ), aRGBAColor.AsArray() ); + [ string addAttribute: attribute value: reinterpret_cast(aColorRef) range: range ]; + CGColorRelease( aColorRef ); +} + ++(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 fontDescriptor:(AquaA11yFontDescriptor*)fontDescriptor { + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + // constants + static const OUString attrUnderline("CharUnderline"); + static const OUString attrBold("CharWeight"); + static const OUString attrFontname("CharFontName"); + static const OUString attrItalic("CharPosture"); + static const OUString attrHeight("CharHeight"); + static const OUString attrStrikethrough("CharStrikeout"); + static const OUString attrShadow("CharShadowed"); + static const OUString attrUnderlineColor("CharUnderlineColor"); + static const OUString attrUnderlineHasColor("CharUnderlineHasColor"); + static const OUString attrForegroundColor("CharColor"); + static const OUString attrBackgroundColor("CharBackColor"); + static const OUString attrSuperscript("CharEscapement"); + static const OUString attrTextAlignment("ParaAdjust"); + // vars + sal_Int32 underlineColor = 0; + bool underlineHasColor = false; + // add attributes to string + for ( const PropertyValue& property : attributes ) { + // 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 != NSUnderlineStyleNone ) { + [ string addAttribute: NSAccessibilityUnderlineTextAttribute value: [ NSNumber numberWithInt: style ] range: range ]; + } + } else if ( property.Name.equals ( attrFontname ) ) { + OUString fontname; + property.Value >>= fontname; + [fontDescriptor setName:CreateNSString(fontname)]; + } else if ( property.Name.equals ( attrBold ) ) { + [fontDescriptor setBold:[AquaA11yTextAttributesWrapper convertBoldStyle:property]]; + } else if ( property.Name.equals ( attrItalic ) ) { + [fontDescriptor setItalic:[AquaA11yTextAttributesWrapper convertItalicStyle:property]]; + } else if ( property.Name.equals ( attrHeight ) ) { + float size; + property.Value >>= size; + [fontDescriptor setSize:size]; + } 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() forAttribute: NSAccessibilityForegroundColorTextAttribute andRange: range toString: string ]; + } else if ( property.Name.equals ( attrBackgroundColor ) ) { + [ AquaA11yTextAttributesWrapper addColor: property.Value.get() 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 ]; + } + } else if ( property.Name.equals ( attrTextAlignment ) ) { + sal_Int32 alignment; + property.Value >>= alignment; + NSNumber *textAlignment = nil; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSCenterTextAlignment' is deprecated: first deprecated in macOS 10.12 + // 'NSJustifiedTextAlignment' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftTextAlignment' is deprecated: first deprecated in macOS 10.12 + // 'NSRightTextAlignment' is deprecated: first deprecated in macOS 10.12 + switch(static_cast(alignment)) { + case css::style::ParagraphAdjust_RIGHT : textAlignment = [NSNumber numberWithInteger:NSRightTextAlignment] ; break; + case css::style::ParagraphAdjust_CENTER: textAlignment = [NSNumber numberWithInteger:NSCenterTextAlignment] ; break; + case css::style::ParagraphAdjust_BLOCK : textAlignment = [NSNumber numberWithInteger:NSJustifiedTextAlignment]; break; + case css::style::ParagraphAdjust_LEFT : + default : textAlignment = [NSNumber numberWithInteger:NSLeftTextAlignment] ; break; + } +SAL_WNODEPRECATED_DECLARATIONS_POP + NSDictionary *paragraphStyle = [NSDictionary dictionaryWithObjectsAndKeys:textAlignment, @"AXTextAlignment", textAlignment, @"AXVisualTextAlignment", nil]; + [string addAttribute:@"AXParagraphStyle" value:paragraphStyle range:range]; + } + } + } + // add underline information + if ( underlineHasColor ) { + [ AquaA11yTextAttributesWrapper addColor: underlineColor forAttribute: NSAccessibilityUnderlineColorTextAttribute andRange: range toString: string ]; + } + // add font information + NSFont * font = [fontDescriptor font]; + [AquaA11yTextAttributesWrapper addFont:font toString:string forRange:range]; + [ pool release ]; +} + ++(void)addMarkup:(XAccessibleTextMarkup*)markup withType:(long)type toString:(NSMutableAttributedString*)string inRange:(NSRange)range { + const long markupCount = markup->getTextMarkupCount(type); + for (long markupIndex = 0; markupIndex < markupCount; ++markupIndex) { + TextSegment markupSegment = markup->getTextMarkup(markupIndex, type); + NSRange markupRange = NSMakeRange(markupSegment.SegmentStart, markupSegment.SegmentEnd - markupSegment.SegmentStart); + markupRange = NSIntersectionRange(range, markupRange); + if (markupRange.length > 0) { + markupRange.location -= range.location; + switch(type) { + case css::text::TextMarkupType::SPELLCHECK: { + [string addAttribute:NSAccessibilityMisspelledTextAttribute value:[NSNumber numberWithBool:YES] range:markupRange]; + [string addAttribute:@"AXMarkedMisspelled" value:[NSNumber numberWithBool:YES] range:markupRange]; + break; + } + } + } + } +} + ++(void)addMarkup:(XAccessibleTextMarkup*)markup toString:(NSMutableAttributedString*)string inRange:(NSRange)range { + [AquaA11yTextAttributesWrapper addMarkup:markup withType:css::text::TextMarkupType::SPELLCHECK toString:string inRange:range]; +} + ++(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 ] && [myString characterAtIndex:0] != 57361) { // TODO: dirty fix for i87817 + [ string beginEditing ]; + // add default attributes for whole string + Sequence < PropertyValue > defaultAttributes = [ wrapper accessibleTextAttributes ] -> getDefaultAttributes ( emptySequence ); + AquaA11yFontDescriptor *defaultFontDescriptor = [[AquaA11yFontDescriptor alloc] init]; + [ AquaA11yTextAttributesWrapper applyAttributesFrom: defaultAttributes toString: string forRange: NSMakeRange ( 0, len ) fontDescriptor: defaultFontDescriptor ]; + // 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 - loc , endOfRange - currentIndex ); + // add run attributes + Sequence < PropertyValue > attributes = [ wrapper accessibleTextAttributes ] -> getRunAttributes ( currentIndex, emptySequence ); + AquaA11yFontDescriptor *fontDescriptor = [[AquaA11yFontDescriptor alloc] initWithDescriptor:defaultFontDescriptor]; + [ AquaA11yTextAttributesWrapper applyAttributesFrom: attributes toString: string forRange: rangeForAttributeRun fontDescriptor: fontDescriptor ]; + [fontDescriptor release]; + currentIndex = textSegment.SegmentEnd; + } + [defaultFontDescriptor release]; + if ([wrapper accessibleTextMarkup]) + [AquaA11yTextAttributesWrapper addMarkup:[wrapper accessibleTextMarkup] toString:string inRange:[origRange rangeValue]]; + [ string endEditing ]; + } + } catch ( IllegalArgumentException & ) { + // empty + } catch ( IndexOutOfBoundsException & ) { + // empty + } catch ( RuntimeException& ) { + // at least don't crash + } + return string; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytextwrapper.h b/vcl/osx/a11ytextwrapper.h new file mode 100644 index 000000000..5d2154ff6 --- /dev/null +++ b/vcl/osx/a11ytextwrapper.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YTEXTWRAPPER_H +#define INCLUDED_VCL_OSX_A11YTEXTWRAPPER_H + +#include +#include + +@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; ++(BOOL)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 // INCLUDED_VCL_OSX_A11YTEXTWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ytextwrapper.mm b/vcl/osx/a11ytextwrapper.mm new file mode 100644 index 000000000..a39037f07 --- /dev/null +++ b/vcl/osx/a11ytextwrapper.mm @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include "a11ytextwrapper.h" +#include "a11ytextattributeswrapper.h" +#include "a11yutil.h" + +#include +#include +#include +#include + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +// 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 + (void)wrapper; + (void)value; +} + ++(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 ] ) { + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + OUString newText = GetOUString ( static_cast(value) ); + NSRange selectedTextRange = [ [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: wrapper ] rangeValue ]; + try { + [ wrapper accessibleEditableText ] -> replaceText ( selectedTextRange.location, selectedTextRange.location + selectedTextRange.length, newText ); + } catch ( const Exception & ) { + // 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 & ) { + // 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 + (void)wrapper; + (void)value; +} + ++(id)sharedTextUIElementsAttributeForElement:(AquaA11yWrapper *)wrapper +{ + return [NSArray arrayWithObject:wrapper]; +} + ++(id)sharedCharacterRangeAttributeForElement:(AquaA11yWrapper *)wrapper +{ + return [ NSValue valueWithRange: NSMakeRange ( 0, [wrapper accessibleText]->getCharacterCount() ) ]; +} + ++(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 ( static_cast([ index intValue ]) ); + lineNumber = [ NSNumber numberWithInt: line ]; + } catch ( IndexOutOfBoundsException & ) { + // 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 & ) { + // 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 & ) { + // 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 & ) { + // empty + } catch ( IllegalArgumentException & ) { + // empty + } + return range; +} + ++(id)rangeForPositionAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)point { + NSValue * value = nil; + css::awt::Point aPoint( [ AquaA11yUtil nsPointToVclPoint: point ]); + const css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); + aPoint.X -= screenPos.X; + aPoint.Y -= screenPos.Y; + sal_Int32 index = [ wrapper accessibleText ] -> getIndexAtPoint( aPoint ); + 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 ] ) { + // get location on screen (must be added since get CharacterBounds returns values relative to parent) + css::awt::Point screenPos = [ wrapper accessibleComponent ] -> getLocationOnScreen(); + css::awt::Point pos ( minx + screenPos.X, miny + screenPos.Y ); + css::awt::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 & ) { + // 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 & ) { + // empty + } catch ( IllegalArgumentException & ) { + // empty + } + return range; +} + ++(id)rTFForRangeAttributeForElement:(AquaA11yWrapper *)wrapper forParameter:(id)range { + NSData * rtfData = nil; + NSAttributedString * attrString = static_cast([ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: wrapper forParameter: range ]); + if ( attrString != nil ) { + @try { + rtfData = [ attrString RTFFromRange: [ range rangeValue ] documentAttributes: @{NSDocumentTypeDocumentAttribute : NSRTFTextDocumentType} ]; + } @catch ( NSException *) { + // empty + } + } + return rtfData; +} + ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper { + bool isSettable = false; + if ( [ attribute isEqualToString: NSAccessibilityValueAttribute ] + || [ attribute isEqualToString: NSAccessibilitySelectedTextAttribute ] + || [ attribute isEqualToString: NSAccessibilitySelectedTextRangeAttribute ] + || [ attribute isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute ] ) { + if ( ! [ [ wrapper accessibilityAttributeValue: NSAccessibilityRoleAttribute ] isEqualToString: NSAccessibilityStaticTextRole ] ) { + isSettable = true; + } + } + return isSettable; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yutil.h b/vcl/osx/a11yutil.h new file mode 100644 index 000000000..56778e76d --- /dev/null +++ b/vcl/osx/a11yutil.h @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YUTIL_H +#define INCLUDED_VCL_OSX_A11YUTIL_H + +#include + +@interface AquaA11yUtil : NSObject { +} ++(NSValue *)vclPointToNSPoint:(css::awt::Point)vclPoint; ++(css::awt::Point)nsPointToVclPoint:(NSValue *)nsPoint; +@end + +#endif // INCLUDED_VCL_OSX_A11YUTIL_H +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yutil.mm b/vcl/osx/a11yutil.mm new file mode 100644 index 000000000..de0389a19 --- /dev/null +++ b/vcl/osx/a11yutil.mm @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11yutil.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 ( static_cast(vclPoint.X), static_cast( 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([ nsPoint pointValue ].x), static_cast(screenRect.size.height - [ nsPoint pointValue ].y) ); +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yvaluewrapper.h b/vcl/osx/a11yvaluewrapper.h new file mode 100644 index 000000000..b4db1de96 --- /dev/null +++ b/vcl/osx/a11yvaluewrapper.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YVALUEWRAPPER_H +#define INCLUDED_VCL_OSX_A11YVALUEWRAPPER_H + +#include +#include +#include + +@interface AquaA11yValueWrapper : NSObject +{ +} ++(id)valueAttributeForElement:(AquaA11yWrapper *)wrapper; ++(id)minValueAttributeForElement:(AquaA11yWrapper *)wrapper; ++(id)maxValueAttributeForElement:(AquaA11yWrapper *)wrapper; ++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames; ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper; ++(void)setValueAttributeForElement:(AquaA11yWrapper *)wrapper to:(id)value; +@end + +#endif // INCLUDED_VCL_OSX_A11YVALUEWRAPPER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11yvaluewrapper.mm b/vcl/osx/a11yvaluewrapper.mm new file mode 100644 index 000000000..4882cd2ef --- /dev/null +++ b/vcl/osx/a11yvaluewrapper.mm @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "a11yvaluewrapper.h" +#include "a11ywrapperstatictext.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 ] ) { + 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 ] ) { + 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 ] ) { + 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 ] ) { + NSNumber * number = static_cast(value); + Any numberAny ( [ number longValue ] ); + [ wrapper accessibleValue ] -> setCurrentValue ( numberAny ); + } +} + ++(void)addAttributeNamesTo:(NSMutableArray *)attributeNames { + [ attributeNames addObject: NSAccessibilityValueAttribute ]; +} + ++(BOOL)isAttributeSettable:(NSString *)attribute forElement:(AquaA11yWrapper *)wrapper { + bool isSettable = false; + if ( [ wrapper accessibleValue ] + && [ attribute isEqualToString: NSAccessibilityValueAttribute ] + && ! [ wrapper isKindOfClass: [ AquaA11yWrapperStaticText class ] ] ) { + isSettable = true; + } + return isSettable; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm new file mode 100644 index 000000000..d3a42058d --- /dev/null +++ b/vcl/osx/a11ywrapper.mm @@ -0,0 +1,1147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include + +#include +#include +#include +#include + +#include + +#include "a11yfocuslistener.hxx" +#include "a11yactionwrapper.h" +#include "a11ycomponentwrapper.h" +#include "a11yselectionwrapper.h" +#include "a11ytablewrapper.h" +#include "a11ytextwrapper.h" +#include "a11yvaluewrapper.h" +#include "a11yrolehelper.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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)accessibleContext; +@end + +static bool isPopupMenuOpen = false; + +static std::ostream &operator<<(std::ostream &s, NSObject *obj) { + return s << [[obj description] UTF8String]; +} + +@implementation AquaA11yWrapper : NSView + +#pragma mark - +#pragma mark Init and dealloc + +-(id)initWithAccessibleContext: (Reference < XAccessibleContext >) rxAccessibleContext { + self = [ super init ]; + if ( self ) { + [ self setDefaults: rxAccessibleContext ]; + } + return self; +} + +-(void) setDefaults: (Reference < XAccessibleContext >) rxAccessibleContext { + mpReferenceWrapper = new ReferenceWrapper; + mActsAsRadioGroup = NO; + mpReferenceWrapper -> rAccessibleContext = rxAccessibleContext; + mIsTableCell = NO; + // Querying all supported interfaces + try { + // XAccessibleComponent + mpReferenceWrapper->rAccessibleComponent.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleExtendedComponent + mpReferenceWrapper->rAccessibleExtendedComponent.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleSelection + mpReferenceWrapper->rAccessibleSelection.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleTable + mpReferenceWrapper->rAccessibleTable.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleText + mpReferenceWrapper->rAccessibleText.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleEditableText + mpReferenceWrapper->rAccessibleEditableText.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleValue + mpReferenceWrapper->rAccessibleValue.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleAction + mpReferenceWrapper->rAccessibleAction.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleTextAttributes + mpReferenceWrapper->rAccessibleTextAttributes.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleMultiLineText + mpReferenceWrapper->rAccessibleMultiLineText.set( rxAccessibleContext, UNO_QUERY ); + // XAccessibleTextMarkup + mpReferenceWrapper->rAccessibleTextMarkup.set( 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 and 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->addAccessibleEventListener( new AquaA11yEventListener( self, rxAccessibleContext -> getAccessibleRole() ) ); + } + } + // TABLE_CELL + if ( rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TABLE_CELL ) { + mIsTableCell = YES; + } + } catch ( const Exception ) { + } +} + +-(void)dealloc { + if ( mpReferenceWrapper ) { + delete mpReferenceWrapper; + } + [ 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:(BOOL)asGetter withGetterParameter:(BOOL)withGetterParameter { + SEL selector = static_cast(nil); + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + @try { + // step 1: create method name from attribute name + NSMutableString * methodName = [ NSMutableString string ]; + if ( ! asGetter ) { + [ methodName appendString: @"set" ]; + } + NSRange const aRange = { 2, 1 }; + NSString * firstChar = [ attribute substringWithRange: aRange ]; // 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 ) { + selector = static_cast(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 > (); +} + +-(BOOL)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 expressed through the hierarchy. An 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 ]; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.10 accessibilityAttributeValue: + return [ super accessibilityAttributeValue: NSAccessibilitySubroleAttribute ]; + SAL_WNODEPRECATED_DECLARATIONS_POP + } + } +} + +-(id)titleAttribute { + return CreateNSString ( [ self accessibleContext ] -> getAccessibleName() ); +} + +-(id)descriptionAttribute { + if ( [ self accessibleContext ] -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) { + return [ self titleAttribute ]; + } else if ( [ self accessibleExtendedComponent ] ) { + 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( false ); + 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 ( const auto& i : relationMemberOf.TargetSet ) { + Reference < XAccessible > rMateAccessible( i, 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 ] ) + { + AquaA11yTableWrapper* pTable = [self isKindOfClass: [AquaA11yTableWrapper class]] ? static_cast(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 = static_cast([ 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 &) { + // TODO: Log + return nil; + } + } +} + +-(id)windowAttribute { + // go upstairs until reaching the broken connection + AquaA11yWrapper * aWrapper = self; + int loops = 0; + while ( [ aWrapper accessibleContext ] -> getAccessibleParent().is() ) { + AquaA11yWrapper *aTentativeParentWrapper = [ AquaA11yFactory wrapperForAccessibleContext: [ aWrapper accessibleContext ] -> getAccessibleParent() -> getAccessibleContext() ]; + // Quick-and-dirty fix for infinite loop after fixing crash in + // fdo#47275 + if ( aTentativeParentWrapper == aWrapper ) + break; + // Even dirtier fix for infinite loop in fdo#55156 + if ( loops++ == 100 ) + break; + aWrapper = aTentativeParentWrapper; + [ aWrapper autorelease ]; + } + // get associated NSWindow + NSWindow* theWindow = [ aWrapper windowForParent ]; + return theWindow; +} + +-(id)topLevelUIElementAttribute { + return [ self windowAttribute ]; +} + +-(id)sizeAttribute { + if ( [ self accessibleComponent ] ) { + return [ AquaA11yComponentWrapper sizeAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)positionAttribute { + if ( [ self accessibleComponent ] ) { + 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 ] ) { + return [ AquaA11yTextWrapper valueAttributeForElement: self ]; + } else if ( [ self accessibleValue ] ) { + return [ AquaA11yValueWrapper valueAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)minValueAttribute { + if ( [ self accessibleValue ] ) { + return [ AquaA11yValueWrapper minValueAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)maxValueAttribute { + if ( [ self accessibleValue ] ) { + return [ AquaA11yValueWrapper maxValueAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)contentsAttribute { + return [ self childrenAttribute ]; +} + +-(id)selectedChildrenAttribute { + return [ AquaA11ySelectionWrapper selectedChildrenAttributeForElement: self ]; +} + +-(id)numberOfCharactersAttribute { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper numberOfCharactersAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)selectedTextAttribute { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper selectedTextAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)selectedTextRangeAttribute { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper selectedTextRangeAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)visibleCharacterRangeAttribute { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper visibleCharacterRangeAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)tabsAttribute { + return self; // TODO ??? +} + +-(id)sharedTextUIElementsAttribute { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper sharedTextUIElementsAttributeForElement: self ]; + } else { + return nil; + } +} + +-(id)sharedCharacterRangeAttribute { + if ( [ self accessibleText ] ) { + 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 ] ) { + return [ AquaA11yTextWrapper stringForRangeAttributeForElement: self forParameter: range ]; + } else { + return nil; + } +} + +-(id)attributedStringForRangeAttributeForParameter:(id)range { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper attributedStringForRangeAttributeForElement: self forParameter: range ]; + } else { + return nil; + } +} + +-(id)rangeForIndexAttributeForParameter:(id)index { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper rangeForIndexAttributeForElement: self forParameter: index ]; + } else { + return nil; + } +} + +-(id)rangeForPositionAttributeForParameter:(id)point { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper rangeForPositionAttributeForElement: self forParameter: point ]; + } else { + return nil; + } +} + +-(id)boundsForRangeAttributeForParameter:(id)range { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper boundsForRangeAttributeForElement: self forParameter: range ]; + } else { + return nil; + } +} + +-(id)styleRangeForIndexAttributeForParameter:(id)index { + if ( [ self accessibleText ] ) { + return [ AquaA11yTextWrapper styleRangeForIndexAttributeForElement: self forParameter: index ]; + } else { + return nil; + } +} + +-(id)rTFForRangeAttributeForParameter:(id)range { + if ( [ self accessibleText ] ) { + 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 ) { + [ 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 ] ) { + return [ AquaA11yTextWrapper lineForIndexAttributeForElement: self forParameter: index ]; + } else { + return nil; + } +} + +-(id)rangeForLineAttributeForParameter:(id)line { + if ( [ self accessibleMultiLineText ] ) { + return [ AquaA11yTextWrapper rangeForLineAttributeForElement: self forParameter: line ]; + } else { + return nil; + } +} + +#pragma mark - +#pragma mark Accessibility Protocol + +-(id)accessibilityAttributeValue:(NSString *)attribute { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << 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 || mIsTableCell ) { + try { + SEL methodSelector = [ self selectorForAttribute: attribute asGetter: YES withGetterParameter: NO ]; + if ( [ self respondsToSelector: methodSelector ] ) { + value = [ self performSelector: methodSelector ]; + } + } catch ( const DisposedException & ) { + mIsTableCell = NO; // just to be sure + [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ]; + return nil; + } catch ( const Exception & ) { + // empty + } + } + if ( theWrapper ) { + [ theWrapper release ]; // the above called method calls retain on the returned Wrapper + } + return value; +} + +-(BOOL)accessibilityIsIgnored { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityIsIgnored]"); + // #i90575# guard NSAccessibility protocol against unwanted access + if ( isPopupMenuOpen ) { + return NO; + } + bool ignored = false; + 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 = true; + break; + default: + ignored = ! ( [ self accessibleContext ] -> getAccessibleStateSet() -> contains ( AccessibleStateType::VISIBLE ) ); + break; + } + return ignored; // TODO: to be completed +} + +-(NSArray *)accessibilityAttributeNames { + SAL_INFO("vcl.a11y", "[" << self << " 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 = static_cast([ AquaA11yRoleHelper getNativeSubroleFrom: [ self accessibleContext ] -> getAccessibleRole() ]); + title = static_cast([ self titleAttribute ]); + Reference < XAccessibleRelationSet > rxRelationSet = [ self accessibleContext ] -> getAccessibleRelationSet(); + // Special Attributes depending on attribute values + if ( nativeSubrole && ! [ nativeSubrole isEqualToString: @"" ] ) { + [ attributeNames addObject: NSAccessibilitySubroleAttribute ]; + } + try + { + nAccessibleChildren = [ self accessibleContext ] -> getAccessibleChildCount(); + if ( nAccessibleChildren > 0 ) { + [ attributeNames addObject: NSAccessibilityChildrenAttribute ]; + } + } + catch( DisposedException& ) {} + catch( RuntimeException& ) {} + + if ( title && ! [ 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 ] ) { + [ AquaA11yTextWrapper addAttributeNamesTo: attributeNames ]; + } + if ( [ self accessibleComponent ] ) { + [ AquaA11yComponentWrapper addAttributeNamesTo: attributeNames ]; + } + if ( [ self accessibleSelection ] ) { + [ AquaA11ySelectionWrapper addAttributeNamesTo: attributeNames ]; + } + if ( [ self accessibleValue ] ) { + [ AquaA11yValueWrapper addAttributeNamesTo: attributeNames ]; + } + [ nativeSubrole release ]; + [ title release ]; + return attributeNames; + } catch ( DisposedException & ) { // Object is no longer available + if ( nativeSubrole ) { + [ nativeSubrole release ]; + } + if ( title ) { + [ title release ]; + } + if ( attributeNames ) { + [ attributeNames release ]; + } + [ AquaA11yFactory removeFromWrapperRepositoryFor: [ self accessibleContext ] ]; + return [ [ NSArray alloc ] init ]; + } +} + +-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeIsSettable:" << attribute << "]"); + bool isSettable = false; + if ( [ self accessibleText ] ) { + isSettable = [ AquaA11yTextWrapper isAttributeSettable: attribute forElement: self ]; + } + if ( ! isSettable && [ self accessibleComponent ] ) { + isSettable = [ AquaA11yComponentWrapper isAttributeSettable: attribute forElement: self ]; + } + if ( ! isSettable && [ self accessibleSelection ] ) { + isSettable = [ AquaA11ySelectionWrapper isAttributeSettable: attribute forElement: self ]; + } + if ( ! isSettable && [ self accessibleValue ] ) { + isSettable = [ AquaA11yValueWrapper isAttributeSettable: attribute forElement: self ]; + } + return isSettable; // TODO: to be completed +} + +-(NSArray *)accessibilityParameterizedAttributeNames { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityParameterizedAttributeNames]"); + NSMutableArray * attributeNames = [ [ NSMutableArray alloc ] init ]; + // Special Attributes depending on interface + if ( [ self accessibleText ] ) { + [ AquaA11yTextWrapper addParameterizedAttributeNamesTo: attributeNames ]; + } + return attributeNames; // TODO: to be completed +} + +-(id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityAttributeValue:" << attribute << " forParameter:" << (static_cast(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 +} + +-(BOOL)accessibilitySetOverrideValue:(id)value forAttribute:(NSString *)attribute +{ + SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetOverrideValue:" << (static_cast(value)) << " forAttribute:" << attribute << "]"); + return NO; // TODO +} + +-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute { + SAL_INFO("vcl.a11y", "[" << self << " accessibilitySetValue:" << (static_cast(value)) << " forAttribute:" << 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 { + SAL_INFO("vcl.a11y", "[" << self << " 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; +} + +-(NSString *)accessibilityActionDescription:(NSString *)action { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionDescription:" << action << "]"); + return NSAccessibilityActionDescription(action); +} + +-(AquaA11yWrapper *)actionResponder { + AquaA11yWrapper * wrapper = nil; + // get some information + NSString * role = static_cast([ self accessibilityAttributeValue: NSAccessibilityRoleAttribute ]); + id enabledAttr = [ self enabledAttribute ]; + bool enabled = [ enabledAttr boolValue ]; + NSView * parent = static_cast([ self accessibilityAttributeValue: NSAccessibilityParentAttribute ]); + AquaA11yWrapper * parentAsWrapper = nil; + if ( [ parent isKindOfClass: [ AquaA11yWrapper class ] ] ) { + parentAsWrapper = static_cast(parent); + } + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.10 accessibilityAttributeValue: + NSString * parentRole = static_cast([ parent accessibilityAttributeValue: NSAccessibilityRoleAttribute ]); + SAL_WNODEPRECATED_DECLARATIONS_POP + // if we are a textarea inside a combobox, then the combobox is the action responder + if ( enabled + && [ role isEqualToString: NSAccessibilityTextAreaRole ] + && [ parentRole isEqualToString: NSAccessibilityComboBoxRole ] + && parentAsWrapper ) { + wrapper = parentAsWrapper; + } else if ( enabled && [ self accessibleAction ] ) { + wrapper = self ; + } + [ parentRole release ]; + [ enabledAttr release ]; + [ role release ]; + return wrapper; +} + +-(void)accessibilityPerformAction:(NSString *)action { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityPerformAction:" << action << "]"); + AquaA11yWrapper * actionResponder = [ self actionResponder ]; + if ( actionResponder ) { + [ AquaA11yActionWrapper doAction: action ofElement: actionResponder ]; + } +} + +-(NSArray *)accessibilityActionNames { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityActionNames]"); + NSArray * actionNames = nil; + AquaA11yWrapper * actionResponder = [ self actionResponder ]; + if ( actionResponder ) { + actionNames = [ AquaA11yActionWrapper actionNamesForElement: actionResponder ]; + } else { + actionNames = [ [ NSArray alloc ] init ]; + } + return actionNames; +} + +#pragma mark - +#pragma mark Hit Test + +-(BOOL)isViewElement:(NSObject *)viewElement hitByPoint:(NSPoint)point { + bool hit = false; + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.10 accessibilityAttributeValue: + NSValue * position = [ viewElement accessibilityAttributeValue: NSAccessibilityPositionAttribute ]; + NSValue * size = [ viewElement accessibilityAttributeValue: NSAccessibilitySizeAttribute ]; + SAL_WNODEPRECATED_DECLARATIONS_POP + if ( position && size ) { + 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 = true; + } + } + [ pool release ]; + return hit; +} + +static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point, + Reference < XAccessibleContext > const & rxAccessibleContext ) { + Reference < XAccessibleContext > hitChild; + Reference < XAccessibleContext > emptyReference; + try { + Reference < XAccessibleComponent > rxAccessibleComponent ( rxAccessibleContext, UNO_QUERY ); + if ( rxAccessibleComponent.is() ) { + css::awt::Point location = rxAccessibleComponent -> getLocationOnScreen(); + css::awt::Point hitPoint ( point.X - location.X , point.Y - location.Y); + Reference < XAccessible > rxAccessible = rxAccessibleComponent -> getAccessibleAtPoint ( hitPoint ); + if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() && + rxAccessible -> getAccessibleContext() -> getAccessibleChildCount() == 0 ) { + hitChild = rxAccessible -> getAccessibleContext(); + } + } + + // iterate the hierarchy looking doing recursive hit testing. + // apparently necessary as a special treatment for e.g. comboboxes + if ( !hitChild.is() ) { + bool bSafeToIterate = true; + sal_Int32 nCount = rxAccessibleContext -> getAccessibleChildCount(); + + if (nCount < 0 || nCount > SAL_MAX_UINT16 /* slow enough for anyone */) + bSafeToIterate = false; + else { // manages descendants is an horror from the a11y standards guys. + Reference< XAccessibleStateSet > xStateSet; + xStateSet = rxAccessibleContext -> getAccessibleStateSet(); + if (xStateSet.is() && xStateSet -> contains(AccessibleStateType::MANAGES_DESCENDANTS ) ) + bSafeToIterate = false; + } + + if( bSafeToIterate ) { + 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 { + SAL_INFO("vcl.a11y", "[" << self << " accessibilityHitTest:" << point << "]"); + static id wrapper = nil; + if ( nil != wrapper ) { + [ wrapper release ]; + wrapper = nil; + } + Reference < XAccessibleContext > hitChild; + NSRect screenRect = [ [ NSScreen mainScreen ] frame ]; + css::awt::Point hitPoint ( static_cast(point.x) , static_cast(screenRect.size.height - point.y) ); + // check child windows first + NSWindow * window = static_cast([ self accessibilityAttributeValue: NSAccessibilityWindowAttribute ]); + NSArray * childWindows = [ window childWindows ]; + if ( [ childWindows count ] > 0 ) { + NSWindow * element = nil; + NSEnumerator * enumerator = [ childWindows objectEnumerator ]; + while ( ( element = [ enumerator nextObject ] ) && !hitChild.is() ) { + if ( [ element isKindOfClass: [ SalFrameWindow class ] ] && [ self isViewElement: element hitByPoint: point ] ) { + // we have a child window that is hit + Reference < XAccessibleRelationSet > relationSet = [ static_cast(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 ( const auto & i : relation.TargetSet ) { + Reference < XAccessible > rxAccessible ( i, UNO_QUERY ); + if ( rxAccessible.is() && rxAccessible -> getAccessibleContext().is() ) { + // hit test for children of parent + hitChild = hitTestRunner ( hitPoint, rxAccessible -> getAccessibleContext() ); + if (hitChild.is()) + break; + } + } + } + } + } + } + // nothing hit yet, so check ourself + if ( ! hitChild.is() ) { + if ( !mpReferenceWrapper ) { + [ self setDefaults: [ self accessibleContext ] ]; + } + hitChild = hitTestRunner ( hitPoint, mpReferenceWrapper -> rAccessibleContext ); + } + if ( hitChild.is() ) { + wrapper = [ AquaA11yFactory wrapperForAccessibleContext: hitChild ]; + } + if ( wrapper ) { + [ 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(); +} + +-(XAccessibleTextMarkup *)accessibleTextMarkup { + return mpReferenceWrapper -> rAccessibleTextMarkup.get(); +} + +-(NSWindow*)windowForParent { + return [self window]; +} + +-(void)setActsAsRadioGroup:(BOOL)actsAsRadioGroup { + mActsAsRadioGroup = actsAsRadioGroup; +} + +-(BOOL)actsAsRadioGroup { + return mActsAsRadioGroup; +} + ++(void)setPopupMenuOpen:(BOOL)popupMenuOpen { + isPopupMenuOpen = popupMenuOpen; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperbutton.h b/vcl/osx/a11ywrapperbutton.h new file mode 100644 index 000000000..23103cd92 --- /dev/null +++ b/vcl/osx/a11ywrapperbutton.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERBUTTON_H +#define INCLUDED_VCL_OSX_A11YWRAPPERBUTTON_H + +#include + +@interface AquaA11yWrapperButton : AquaA11yWrapper +{ +} +-(id)valueAttribute; +-(id)descriptionAttribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERBUTTON_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperbutton.mm b/vcl/osx/a11ywrapperbutton.mm new file mode 100644 index 000000000..ca5f16af3 --- /dev/null +++ b/vcl/osx/a11ywrapperbutton.mm @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrapperbutton.h" +#include "a11ytextwrapper.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappercheckbox.h b/vcl/osx/a11ywrappercheckbox.h new file mode 100644 index 000000000..6f20a888b --- /dev/null +++ b/vcl/osx/a11ywrappercheckbox.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERCHECKBOX_H +#define INCLUDED_VCL_OSX_A11YWRAPPERCHECKBOX_H + +#include + +@interface AquaA11yWrapperCheckBox : AquaA11yWrapper +{ +} +-(id)valueAttribute; +-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERCHECKBOX_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappercheckbox.mm b/vcl/osx/a11ywrappercheckbox.mm new file mode 100644 index 000000000..d67c5b610 --- /dev/null +++ b/vcl/osx/a11ywrappercheckbox.mm @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrappercheckbox.h" +#include "a11yvaluewrapper.h" +#include "a11ytextwrapper.h" + +// Wrapper for AXCheckbox role + +@implementation AquaA11yWrapperCheckBox : AquaA11yWrapper + +-(id)valueAttribute { + if ( [ self accessibleValue ] ) { + return [ AquaA11yValueWrapper valueAttributeForElement: self ]; + } + return [ NSNumber numberWithInt: 0 ]; +} + +-(BOOL)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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappercombobox.h b/vcl/osx/a11ywrappercombobox.h new file mode 100644 index 000000000..7995f06b6 --- /dev/null +++ b/vcl/osx/a11ywrappercombobox.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERCOMBOBOX_H +#define INCLUDED_VCL_OSX_A11YWRAPPERCOMBOBOX_H + +#include +#include + +@interface AquaA11yWrapperComboBox : AquaA11yWrapper +{ + AquaA11yWrapper * textArea; +} +-(id)initWithAccessibleContext: (css::uno::Reference < css::accessibility::XAccessibleContext >) anAccessibleContext; +-(id)valueAttribute; +-(id)numberOfCharactersAttribute; +-(id)selectedTextAttribute; +-(id)selectedTextRangeAttribute; +-(id)visibleCharacterRangeAttribute; +// Accessibility Protocol +-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute; +-(void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERCOMBOBOX_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappercombobox.mm b/vcl/osx/a11ywrappercombobox.mm new file mode 100644 index 000000000..962a66914 --- /dev/null +++ b/vcl/osx/a11ywrappercombobox.mm @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrappercombobox.h" +#include "a11yrolehelper.h" + +#include + +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 = static_cast(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 + +-(BOOL)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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappergroup.h b/vcl/osx/a11ywrappergroup.h new file mode 100644 index 000000000..5309c155b --- /dev/null +++ b/vcl/osx/a11ywrappergroup.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERGROUP_H +#define INCLUDED_VCL_OSX_A11YWRAPPERGROUP_H + +#include + +@interface AquaA11yWrapperGroup : AquaA11yWrapper +{ +} +-(id)titleUIElementAttribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERGROUP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappergroup.mm b/vcl/osx/a11ywrappergroup.mm new file mode 100644 index 000000000..39cbd9adf --- /dev/null +++ b/vcl/osx/a11ywrappergroup.mm @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrappergroup.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperlist.h b/vcl/osx/a11ywrapperlist.h new file mode 100644 index 000000000..8864555f2 --- /dev/null +++ b/vcl/osx/a11ywrapperlist.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERLIST_H +#define INCLUDED_VCL_OSX_A11YWRAPPERLIST_H + +#include + +@interface AquaA11yWrapperList : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERLIST_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperlist.mm b/vcl/osx/a11ywrapperlist.mm new file mode 100644 index 000000000..9b0bac733 --- /dev/null +++ b/vcl/osx/a11ywrapperlist.mm @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrapperlist.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperradiobutton.h b/vcl/osx/a11ywrapperradiobutton.h new file mode 100644 index 000000000..ec8999f36 --- /dev/null +++ b/vcl/osx/a11ywrapperradiobutton.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERRADIOBUTTON_H +#define INCLUDED_VCL_OSX_A11YWRAPPERRADIOBUTTON_H + +#include + +@interface AquaA11yWrapperRadioButton : AquaA11yWrapper +{ +} +-(id)valueAttribute; +-(BOOL)accessibilityIsAttributeSettable:(NSString *)attribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERRADIOBUTTON_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperradiobutton.mm b/vcl/osx/a11ywrapperradiobutton.mm new file mode 100644 index 000000000..21fd9529b --- /dev/null +++ b/vcl/osx/a11ywrapperradiobutton.mm @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrapperradiobutton.h" +#include "a11ytextwrapper.h" +#include "a11yvaluewrapper.h" + +// Wrapper for AXRadioButton role + +@implementation AquaA11yWrapperRadioButton : AquaA11yWrapper + +-(id)valueAttribute { + if ( [ self accessibleValue ] ) { + return [ AquaA11yValueWrapper valueAttributeForElement: self ]; + } + return [ NSNumber numberWithInt: 0 ]; +} + +-(BOOL)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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperradiogroup.h b/vcl/osx/a11ywrapperradiogroup.h new file mode 100644 index 000000000..98e5a5cf5 --- /dev/null +++ b/vcl/osx/a11ywrapperradiogroup.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERRADIOGROUP_H +#define INCLUDED_VCL_OSX_A11YWRAPPERRADIOGROUP_H + +#include + +@interface AquaA11yWrapperRadioGroup : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERRADIOGROUP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperradiogroup.mm b/vcl/osx/a11ywrapperradiogroup.mm new file mode 100644 index 000000000..557e0b1bc --- /dev/null +++ b/vcl/osx/a11ywrapperradiogroup.mm @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrapperradiogroup.h" +#include "a11ytextwrapper.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperrow.h b/vcl/osx/a11ywrapperrow.h new file mode 100644 index 000000000..00e32f4df --- /dev/null +++ b/vcl/osx/a11ywrapperrow.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERROW_H +#define INCLUDED_VCL_OSX_A11YWRAPPERROW_H + +#include + +@interface AquaA11yWrapperRow : AquaA11yWrapper +{ +} +-(id)disclosingAttribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERROW_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperrow.mm b/vcl/osx/a11ywrapperrow.mm new file mode 100644 index 000000000..1b7ee56dd --- /dev/null +++ b/vcl/osx/a11ywrapperrow.mm @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrapperrow.h" +#include "a11ytextwrapper.h" + +// Wrapper for AXRow role + +@implementation AquaA11yWrapperRow : AquaA11yWrapper + +-(id)disclosingAttribute { + // TODO: implement + return nil; +} + +-(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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperscrollarea.h b/vcl/osx/a11ywrapperscrollarea.h new file mode 100644 index 000000000..c1556f9a9 --- /dev/null +++ b/vcl/osx/a11ywrapperscrollarea.h @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERSCROLLAREA_H +#define INCLUDED_VCL_OSX_A11YWRAPPERSCROLLAREA_H + +#include + +@interface AquaA11yWrapperScrollArea : AquaA11yWrapper +{ +} +-(id)verticalScrollBarAttribute; +-(id)horizontalScrollBarAttribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERSCROLLAREA_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperscrollarea.mm b/vcl/osx/a11ywrapperscrollarea.mm new file mode 100644 index 000000000..b0b963a6b --- /dev/null +++ b/vcl/osx/a11ywrapperscrollarea.mm @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrapperscrollarea.h" +#include "a11ywrapperscrollbar.h" +#include "a11yrolehelper.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 = static_cast(child); + if ( [ element isKindOfClass: [ AquaA11yWrapperScrollBar class ] ] ) { + AquaA11yWrapperScrollBar * scrollBar = static_cast(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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperscrollbar.h b/vcl/osx/a11ywrapperscrollbar.h new file mode 100644 index 000000000..88beceb4f --- /dev/null +++ b/vcl/osx/a11ywrapperscrollbar.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERSCROLLBAR_H +#define INCLUDED_VCL_OSX_A11YWRAPPERSCROLLBAR_H + +#include + +@interface AquaA11yWrapperScrollBar : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERSCROLLBAR_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperscrollbar.mm b/vcl/osx/a11ywrapperscrollbar.mm new file mode 100644 index 000000000..a4b7a246b --- /dev/null +++ b/vcl/osx/a11ywrapperscrollbar.mm @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include "a11ywrapperscrollbar.h" + +#include + +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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappersplitter.h b/vcl/osx/a11ywrappersplitter.h new file mode 100644 index 000000000..22397e869 --- /dev/null +++ b/vcl/osx/a11ywrappersplitter.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERSPLITTER_H +#define INCLUDED_VCL_OSX_A11YWRAPPERSPLITTER_H + +#include + +@interface AquaA11yWrapperSplitter : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERSPLITTER_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappersplitter.mm b/vcl/osx/a11ywrappersplitter.mm new file mode 100644 index 000000000..b43928bd4 --- /dev/null +++ b/vcl/osx/a11ywrappersplitter.mm @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrappersplitter.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperstatictext.h b/vcl/osx/a11ywrapperstatictext.h new file mode 100644 index 000000000..c02a1f3b8 --- /dev/null +++ b/vcl/osx/a11ywrapperstatictext.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERSTATICTEXT_H +#define INCLUDED_VCL_OSX_A11YWRAPPERSTATICTEXT_H + +#include + +@interface AquaA11yWrapperStaticText : AquaA11yWrapper +{ +} +-(id)titleAttribute; +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERSTATICTEXT_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrapperstatictext.mm b/vcl/osx/a11ywrapperstatictext.mm new file mode 100644 index 000000000..cd4728544 --- /dev/null +++ b/vcl/osx/a11ywrapperstatictext.mm @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrapperstatictext.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertabgroup.h b/vcl/osx/a11ywrappertabgroup.h new file mode 100644 index 000000000..38c12ed21 --- /dev/null +++ b/vcl/osx/a11ywrappertabgroup.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERTABGROUP_H +#define INCLUDED_VCL_OSX_A11YWRAPPERTABGROUP_H + +#include + +@interface AquaA11yWrapperTabGroup : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERTABGROUP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertabgroup.mm b/vcl/osx/a11ywrappertabgroup.mm new file mode 100644 index 000000000..ad5971865 --- /dev/null +++ b/vcl/osx/a11ywrappertabgroup.mm @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrappertabgroup.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertextarea.h b/vcl/osx/a11ywrappertextarea.h new file mode 100644 index 000000000..325284973 --- /dev/null +++ b/vcl/osx/a11ywrappertextarea.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERTEXTAREA_H +#define INCLUDED_VCL_OSX_A11YWRAPPERTEXTAREA_H + +#include + +@interface AquaA11yWrapperTextArea : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERTEXTAREA_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertextarea.mm b/vcl/osx/a11ywrappertextarea.mm new file mode 100644 index 000000000..3f51f3541 --- /dev/null +++ b/vcl/osx/a11ywrappertextarea.mm @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrappertextarea.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertoolbar.h b/vcl/osx/a11ywrappertoolbar.h new file mode 100644 index 000000000..d8871a507 --- /dev/null +++ b/vcl/osx/a11ywrappertoolbar.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_A11YWRAPPERTOOLBAR_H +#define INCLUDED_VCL_OSX_A11YWRAPPERTOOLBAR_H + +#include + +@interface AquaA11yWrapperToolbar : AquaA11yWrapper +{ +} +-(NSArray *)accessibilityAttributeNames; +@end + +#endif // INCLUDED_VCL_OSX_A11YWRAPPERTOOLBAR_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/a11ywrappertoolbar.mm b/vcl/osx/a11ywrappertoolbar.mm new file mode 100644 index 000000000..05e9b30e2 --- /dev/null +++ b/vcl/osx/a11ywrappertoolbar.mm @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "a11ywrappertoolbar.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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/clipboard.cxx b/vcl/osx/clipboard.cxx new file mode 100644 index 000000000..c2adb5bfc --- /dev/null +++ b/vcl/osx/clipboard.cxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "clipboard.hxx" + +#include "DataFlavorMapping.hxx" +#include "OSXTransferable.hxx" +#include +#include +#include +#include + +using namespace css; + +@implementation EventListener; + +-(EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb +{ + self = [super init]; + + if (self) + pAquaClipboard = pcb; + + return self; +} + +-(void)pasteboard:(NSPasteboard*)sender provideDataForType:(const NSString*)type +{ + if( pAquaClipboard ) + pAquaClipboard->provideDataForType(sender, type); +} + +-(void)applicationDidBecomeActive:(NSNotification*)aNotification +{ + if( pAquaClipboard ) + pAquaClipboard->applicationDidBecomeActive(aNotification); +} + +-(void)disposing +{ + pAquaClipboard = nullptr; +} + +@end + +static OUString clipboard_getImplementationName() +{ + return "com.sun.star.datatransfer.clipboard.AquaClipboard"; +} + +static uno::Sequence clipboard_getSupportedServiceNames() +{ + return { OUString("com.sun.star.datatransfer.clipboard.SystemClipboard") }; +} + +AquaClipboard::AquaClipboard(NSPasteboard* pasteboard, bool bUseSystemPasteboard) + : WeakComponentImplHelper(m_aMutex) + , mIsSystemPasteboard(bUseSystemPasteboard) +{ + uno::Reference xContext = comphelper::getProcessComponentContext(); + + mrXMimeCntFactory = datatransfer::MimeContentTypeFactory::create(xContext); + + mpDataFlavorMapper = std::make_shared(); + + if (pasteboard != nullptr) + { + mPasteboard = pasteboard; + mIsSystemPasteboard = false; + } + else + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.13 NSDragPboard + mPasteboard = bUseSystemPasteboard ? [NSPasteboard generalPasteboard] : + [NSPasteboard pasteboardWithName: NSDragPboard]; + SAL_WNODEPRECATED_DECLARATIONS_POP + + if (mPasteboard == nil) + { + throw uno::RuntimeException("AquaClipboard: Cannot create Cocoa pasteboard", + static_cast(this)); + } + } + + [mPasteboard retain]; + + mEventListener = [[EventListener alloc] initWithAquaClipboard: this]; + + if (mEventListener == nil) + { + [mPasteboard release]; + + throw uno::RuntimeException( + "AquaClipboard: Cannot create pasteboard change listener", + static_cast(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]; +} + +uno::Reference SAL_CALL AquaClipboard::getContents() +{ + osl::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 uno::Reference( + new OSXTransferable(mrXMimeCntFactory, + mpDataFlavorMapper, + mPasteboard)); +} + +void SAL_CALL AquaClipboard::setContents( + uno::Reference const & xTransferable, + uno::Reference const & xClipboardOwner) +{ + NSArray* types = xTransferable.is() ? + mpDataFlavorMapper->flavorSequenceToTypesArray(xTransferable->getTransferDataFlavors()) : + [NSArray array]; + + osl::ClearableMutexGuard aGuard(m_aMutex); + + uno::Reference oldOwner(mXClipboardOwner); + mXClipboardOwner = xClipboardOwner; + + uno::Reference 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() +{ + return OUString(); +} + +sal_Int8 SAL_CALL AquaClipboard::getRenderingCapabilities() +{ + return 0; +} + +void SAL_CALL AquaClipboard::addClipboardListener(uno::Reference const & listener) +{ + osl::MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw lang::IllegalArgumentException("empty reference", + static_cast(this), 1); + + mClipboardListeners.push_back(listener); +} + +void SAL_CALL AquaClipboard::removeClipboardListener(uno::Reference const & listener) +{ + osl::MutexGuard aGuard(m_aMutex); + + if (!listener.is()) + throw lang::IllegalArgumentException("empty reference", + static_cast(this), 1); + + mClipboardListeners.remove(listener); +} + +void AquaClipboard::applicationDidBecomeActive(NSNotification*) +{ + osl::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 + uno::Reference oldOwner(mXClipboardOwner); + mXClipboardOwner.clear(); + + uno::Reference oldContent(mXClipboardContent); + mXClipboardContent.clear(); + + aGuard.clear(); + + if (oldOwner.is()) + { + fireLostClipboardOwnershipEvent(oldOwner, oldContent); + } + + fireClipboardChangedEvent(); + } +} + +void AquaClipboard::fireClipboardChangedEvent() +{ + osl::ClearableMutexGuard aGuard(m_aMutex); + + datatransfer::clipboard::ClipboardEvent aEvent; + + if (!mClipboardListeners.empty()) + { + aEvent = datatransfer::clipboard::ClipboardEvent(static_cast(this), getContents()); + } + + aGuard.clear(); + + for (auto const& rListener : mClipboardListeners) + { + if (rListener.is()) + { + try + { + rListener->changedContents(aEvent); + } + catch (uno::RuntimeException& ) + {} + } + } +} + +void AquaClipboard::fireLostClipboardOwnershipEvent( + uno::Reference const & rOldOwner, + uno::Reference const & rOldContent) +{ + assert(rOldOwner.is()); + + try + { + rOldOwner->lostOwnership(static_cast(this), rOldContent); + } + catch(uno::RuntimeException&) + {} +} + +void AquaClipboard::provideDataForType(NSPasteboard* sender, const NSString* type) +{ + if( mXClipboardContent.is() ) + { + DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(type, mXClipboardContent); + NSData* pBoardData = nullptr; + + if (dp.get() != nullptr) + { + pBoardData = dp->getSystemData(); + [sender setData: pBoardData forType:const_cast(type)]; + } + } +} + +void SAL_CALL AquaClipboard::flushClipboard() +{ + if (mXClipboardContent.is()) + { + uno::Sequence flavorList = mXClipboardContent->getTransferDataFlavors(); + sal_uInt32 nFlavors = flavorList.getLength(); + bool bInternal(false); + + for (sal_uInt32 i = 0; i < nFlavors; i++) + { + const NSString* sysType = mpDataFlavorMapper->openOfficeToSystemFlavor(flavorList[i], bInternal); + + if (sysType != nullptr) + { + provideDataForType(mPasteboard, sysType); + } + } + mXClipboardContent.clear(); + } +} + +NSPasteboard* AquaClipboard::getPasteboard() const +{ + return mPasteboard; +} + +OUString SAL_CALL AquaClipboard::getImplementationName() +{ + return clipboard_getImplementationName(); +} + +sal_Bool SAL_CALL AquaClipboard::supportsService(OUString const & rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence SAL_CALL AquaClipboard::getSupportedServiceNames() +{ + return clipboard_getSupportedServiceNames(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/clipboard.hxx b/vcl/osx/clipboard.hxx new file mode 100644 index 000000000..2bfbd6cf6 --- /dev/null +++ b/vcl/osx/clipboard.hxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_CLIPBOARD_HXX +#define INCLUDED_VCL_OSX_CLIPBOARD_HXX + +#include "DataFlavorMapping.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#import +#include + +class AquaClipboard; + +@interface EventListener : NSObject +{ + AquaClipboard* pAquaClipboard; +} + +// Init the pasteboard change listener with a reference to the OfficeClipboard +// instance +- (EventListener*)initWithAquaClipboard: (AquaClipboard*) pcb; + +// Promise resolver function +- (void)pasteboard:(NSPasteboard*)sender provideDataForType:(const NSString *)type; + +-(void)applicationDidBecomeActive:(NSNotification*)aNotification; + +-(void)disposing; +@end + +class AquaClipboard : public ::cppu::BaseMutex, + public ::cppu::WeakComponentImplHelper +{ +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, + bool bUseSystemClipboard); + + virtual ~AquaClipboard() override; + AquaClipboard(const AquaClipboard&) = delete; + AquaClipboard& operator=(const AquaClipboard&) = delete; + + // XClipboard + + virtual css::uno::Reference SAL_CALL getContents() override; + + virtual void SAL_CALL setContents(css::uno::Reference const & xTransferable, + css::uno::Reference const & xClipboardOwner) override; + + virtual OUString SAL_CALL getName() override; + + // XClipboardEx + + virtual sal_Int8 SAL_CALL getRenderingCapabilities() override; + + // XClipboardNotifier + + virtual void SAL_CALL addClipboardListener(css::uno::Reference const & listener) override; + virtual void SAL_CALL removeClipboardListener(css::uno::Reference const & listener) override; + + // XFlushableClipboard + + virtual void SAL_CALL flushClipboard() override; + + // XServiceInfo + + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + /* 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(css::uno::Reference const & oldOwner, + css::uno::Reference const & oldContent); + + void pasteboardChangedOwner(); + + void provideDataForType(NSPasteboard* sender, const NSString* type); + + void applicationDidBecomeActive(NSNotification* aNotification); + +private: + + /* Notify all registered XClipboardListener that the clipboard content + has changed. + */ + void fireClipboardChangedEvent(); + +private: + css::uno::Reference mrXMimeCntFactory; + std::list> mClipboardListeners; + css::uno::Reference mXClipboardContent; + css::uno::Reference mXClipboardOwner; + DataFlavorMapperPtr_t mpDataFlavorMapper; + bool mIsSystemPasteboard; + NSPasteboard* mPasteboard; + int mPasteboardChangeCount; + EventListener* mEventListener; +}; + +#endif // INCLUDED_VCL_OSX_CLIPBOARD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/cuidraw.hxx b/vcl/osx/cuidraw.hxx new file mode 100644 index 000000000..02cd2cdc3 --- /dev/null +++ b/vcl/osx/cuidraw.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_CUIDRAW_HXX +#define INCLUDED_VCL_OSX_CUIDRAW_HXX + +#include + +#include +#include +#include + +#include + +#if !HAVE_FEATURE_MACOSX_SANDBOX + +extern "C" { + +typedef CFTypeRef CUIRendererRef; + +void CUIDraw( + CUIRendererRef r, CGRect rect, CGContextRef ctx, CFDictionaryRef options, + CFDictionaryRef * result); + +} + +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/documentfocuslistener.cxx b/vcl/osx/documentfocuslistener.cxx new file mode 100644 index 000000000..494a3a945 --- /dev/null +++ b/vcl/osx/documentfocuslistener.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "documentfocuslistener.hxx" + +#include +#include +#include +#include +#include + +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 ) +{ + // 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 ) +{ + try { + switch( aEvent.EventId ) + { + case AccessibleEventId::STATE_CHANGED: + { + sal_Int16 nState = AccessibleStateType::INVALID; + aEvent.NewValue >>= nState; + + if( AccessibleStateType::FOCUSED == nState ) + m_aFocusTracker.setFocusedObject( getAccessible(aEvent) ); + } + 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); + SAL_INFO("vcl", "Invalidate all children called" ); + } + break; + + default: + break; + } + } + catch (const IndexOutOfBoundsException&) + { + SAL_WARN("vcl", "Focused object has invalid index in parent"); + } +} + +Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject& aEvent ) +{ + 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) +{ + Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext(); + + if( xContext.is() ) + attachRecursive(xAccessible, xContext); +} + +void DocumentFocusListener::attachRecursive( + const Reference< XAccessible >& xAccessible, + const Reference< XAccessibleContext >& xContext +) +{ + 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 +) +{ + if( xStateSet->contains(AccessibleStateType::FOCUSED ) ) + m_aFocusTracker.setFocusedObject( xAccessible ); + + Reference< XAccessibleEventBroadcaster > xBroadcaster(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->addAccessibleEventListener(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) +{ + Reference< XAccessibleContext > xContext = xAccessible->getAccessibleContext(); + + if( xContext.is() ) + detachRecursive(xAccessible, xContext); +} + +void DocumentFocusListener::detachRecursive( + const Reference< XAccessible >& xAccessible, + const Reference< XAccessibleContext >& xContext +) +{ + 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 +) +{ + Reference< XAccessibleEventBroadcaster > xBroadcaster(xContext, UNO_QUERY); + + if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) ) + { + xBroadcaster->removeAccessibleEventListener(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); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/documentfocuslistener.hxx b/vcl/osx/documentfocuslistener.hxx new file mode 100644 index 000000000..93bc8136a --- /dev/null +++ b/vcl/osx/documentfocuslistener.hxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OSX_DOCUMENTFOCUSLISTENER_HXX +#define INCLUDED_VCL_OSX_DOCUMENTFOCUSLISTENER_HXX + +#include + +#include + +#include + +#include + + +class DocumentFocusListener : + public ::cppu::WeakImplHelper< css::accessibility::XAccessibleEventListener > +{ + +public: + + explicit DocumentFocusListener(AquaA11yFocusTracker& rTracker); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void attachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void attachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible, + const css::uno::Reference< css::accessibility::XAccessibleContext >& xContext + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void attachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible, + const css::uno::Reference< css::accessibility::XAccessibleContext >& xContext, + const css::uno::Reference< css::accessibility::XAccessibleStateSet >& xStateSet + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void detachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void detachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible, + const css::uno::Reference< css::accessibility::XAccessibleContext >& xContext + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + void detachRecursive( + const css::uno::Reference< css::accessibility::XAccessible >& xAccessible, + const css::uno::Reference< css::accessibility::XAccessibleContext >& xContext, + const css::uno::Reference< css::accessibility::XAccessibleStateSet >& xStateSet + ); + + /// @throws css::lang::IndexOutOfBoundsException + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::accessibility::XAccessible > getAccessible(const css::lang::EventObject& aEvent ); + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XAccessibleEventListener + virtual void SAL_CALL notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) override; + +private: + std::set< css::uno::Reference< css::uno::XInterface > > m_aRefList; + + AquaA11yFocusTracker& m_aFocusTracker; +}; + +#endif // INCLUDED_VCL_OSX_DOCUMENTFOCUSLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/printaccessoryview.mm b/vcl/osx/printaccessoryview.mm new file mode 100644 index 000000000..932b65dd3 --- /dev/null +++ b/vcl/osx/printaccessoryview.mm @@ -0,0 +1,1268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace vcl; +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; + +namespace { + +class ControllerProperties; + +} + +@interface ControlTarget : NSObject +{ + ControllerProperties* mpController; +} +-(id)initWithControllerMap: (ControllerProperties*)pController; +-(void)triggered:(id)pSender; +-(void)triggeredNumeric:(id)pSender; +-(void)dealloc; +@end + +@interface AquaPrintPanelAccessoryController : NSViewController< NSPrintPanelAccessorizing > +{ + NSPrintOperation *mpPrintOperation; + vcl::PrinterController *mpPrinterController; + PrintAccessoryViewState *mpViewState; +} + +-(void)forPrintOperation:(NSPrintOperation*)pPrintOp; +-(void)withPrinterController:(vcl::PrinterController*)pController; +-(void)withViewState:(PrintAccessoryViewState*)pState; + +-(NSPrintOperation*)printOperation; +-(vcl::PrinterController*)printerController; +-(PrintAccessoryViewState*)viewState; + +-(NSSet*)keyPathsForValuesAffectingPreview; +-(NSArray*)localizedSummaryItems; + +-(sal_Int32)updatePrintOperation:(sal_Int32)pLastPageCount; + +@end + +@implementation AquaPrintPanelAccessoryController + +-(void)forPrintOperation:(NSPrintOperation*)pPrintOp + { mpPrintOperation = pPrintOp; } + +-(void)withPrinterController:(vcl::PrinterController*)pController + { mpPrinterController = pController; } + +-(void)withViewState:(PrintAccessoryViewState*)pState + { mpViewState = pState; } + +-(NSPrintOperation*)printOperation + { return mpPrintOperation; } + +-(vcl::PrinterController*)printerController + { return mpPrinterController; } + +-(PrintAccessoryViewState*)viewState + { return mpViewState; } + +-(NSSet*)keyPathsForValuesAffectingPreview +{ + return [ NSSet setWithObject:@"updatePrintOperation" ]; +} + +-(NSArray*)localizedSummaryItems +{ + return [ NSArray arrayWithObject: + [ NSDictionary dictionary ] ]; +} + +-(sal_Int32)updatePrintOperation:(sal_Int32)pLastPageCount +{ + // page range may be changed by option choice + sal_Int32 nPages = mpPrinterController->getFilteredPageCount(); + + mpViewState->bNeedRestart = false; + if( nPages != pLastPageCount ) + { + #if OSL_DEBUG_LEVEL > 1 + SAL_INFO( "vcl.osx.print", "number of pages changed" << + " from " << pLastPageCount << " to " << nPages ); + #endif + mpViewState->bNeedRestart = true; + } + + NSTabView* pTabView = [[[self view] subviews] objectAtIndex:0]; + NSTabViewItem* pItem = [pTabView selectedTabViewItem]; + if( pItem ) + mpViewState->nLastPage = [pTabView indexOfTabViewItem: pItem]; + else + mpViewState->nLastPage = 0; + + if( mpViewState->bNeedRestart ) + { + // AppKit does not give a chance of changing the page count + // and don't let cancel the dialog either + // hack: send a cancel message to the modal window displaying views + NSWindow* pNSWindow = [NSApp modalWindow]; + if( pNSWindow ) + [pNSWindow cancelOperation: nil]; + [[mpPrintOperation printInfo] setJobDisposition: NSPrintCancelJob]; + } + + return nPages; +} + +@end + +namespace { + +class ControllerProperties +{ + std::map< int, OUString > maTagToPropertyName; + std::map< int, sal_Int32 > maTagToValueInt; + std::map< NSView*, NSView* > maViewPairMap; + std::vector< NSObject* > maViews; + int mnNextTag; + sal_Int32 mnLastPageCount; + AquaPrintPanelAccessoryController* mpAccessoryController; + +public: + ControllerProperties( AquaPrintPanelAccessoryController* i_pAccessoryController ) + : mnNextTag( 0 ) + , mnLastPageCount( [i_pAccessoryController printerController]->getFilteredPageCount() ) + , mpAccessoryController( i_pAccessoryController ) + { + static_assert( SAL_N_ELEMENTS(SV_PRINT_NATIVE_STRINGS) == 5, "resources not found" ); + } + + static OUString getMoreString() + { + return VclResId(SV_PRINT_NATIVE_STRINGS[3]); + } + + static OUString getPrintSelectionString() + { + return VclResId(SV_PRINT_NATIVE_STRINGS[4]); + } + + int addNameTag( const OUString& i_rPropertyName ) + { + int nNewTag = mnNextTag++; + maTagToPropertyName[ nNewTag ] = i_rPropertyName; + return nNewTag; + } + + int addNameAndValueTag( const 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, 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() ) + { + vcl::PrinterController * mpController = [mpAccessoryController printerController]; + PropertyValue* pVal = mpController->getValue( name_it->second ); + if( pVal ) + { + pVal->Value <<= value_it->second; + mnLastPageCount = [mpAccessoryController updatePrintOperation: mnLastPageCount]; + } + } + } + + void changePropertyWithIntValue( int i_nTag, sal_Int64 i_nValue ) + { + std::map< int, OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); + if( name_it != maTagToPropertyName.end() ) + { + vcl::PrinterController * mpController = [mpAccessoryController printerController]; + PropertyValue* pVal = mpController->getValue( name_it->second ); + if( pVal ) + { + pVal->Value <<= i_nValue; + mnLastPageCount = [mpAccessoryController updatePrintOperation: mnLastPageCount]; + } + } + } + + void changePropertyWithBoolValue( int i_nTag, bool i_bValue ) + { + std::map< int, OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); + if( name_it != maTagToPropertyName.end() ) + { + vcl::PrinterController * mpController = [mpAccessoryController printerController]; + PropertyValue* pVal = mpController->getValue( name_it->second ); + if( pVal ) + { + // ugly + if( name_it->second == "PrintContent" ) + pVal->Value <<= i_bValue ? sal_Int32(2) : sal_Int32(0); + else + pVal->Value <<= i_bValue; + + mnLastPageCount = [mpAccessoryController updatePrintOperation: mnLastPageCount]; + } + } + } + + void changePropertyWithStringValue( int i_nTag, const OUString& i_rValue ) + { + std::map< int, OUString >::const_iterator name_it = maTagToPropertyName.find( i_nTag ); + if( name_it != maTagToPropertyName.end() ) + { + vcl::PrinterController * mpController = [mpAccessoryController printerController]; + PropertyValue* pVal = mpController->getValue( name_it->second ); + if( pVal ) + { + pVal->Value <<= i_rValue; + mnLastPageCount = [mpAccessoryController updatePrintOperation: mnLastPageCount]; + } + } + } + + 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 = static_cast(pObj); + else if( [pObj isKindOfClass: [NSCell class]] ) + pCell = static_cast(pObj); + + int nTag = pCtrl ? [pCtrl tag] : + pCell ? [pCell tag] : + -1; + + std::map< int, OUString >::const_iterator name_it = maTagToPropertyName.find( nTag ); + if( name_it != maTagToPropertyName.end() && name_it->second != "PrintContent" ) + { + vcl::PrinterController * mpController = [mpAccessoryController printerController]; + bool bEnabled = mpController->isUIOptionEnabled( name_it->second ) ? YES : NO; + if( pCtrl ) + { + [pCtrl setEnabled: bEnabled]; + NSView* pOther = getPair( pCtrl ); + if( pOther && [pOther isKindOfClass: [NSControl class]] ) + [static_cast(pOther) setEnabled: bEnabled]; + } + else if( pCell ) + [pCell setEnabled: bEnabled]; + } + } + } + +}; + +} + +static OUString filterAccelerator( OUString const & rText ) +{ + OUStringBuffer aBuf( rText.getLength() ); + for( sal_Int32 nIndex = 0; nIndex != -1; ) + aBuf.append( rText.getToken( 0, '~', nIndex ) ); + return 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 = static_cast(pSender); + NSMenuItem* pSelected = [pBtn selectedItem]; + if( pSelected ) + { + int nTag = [pSelected tag]; + mpController->changePropertyWithIntValue( nTag ); + } + } + else if( [pSender isMemberOfClass: [NSButton class]] ) + { + NSButton* pBtn = static_cast(pSender); + int nTag = [pBtn tag]; + mpController->changePropertyWithBoolValue( nTag, [pBtn state] == NSControlStateValueOn ); + } + else if( [pSender isMemberOfClass: [NSMatrix class]] ) + { + NSObject* pObj = [static_cast(pSender) selectedCell]; + if( [pObj isMemberOfClass: [NSButtonCell class]] ) + { + NSButtonCell* pCell = static_cast(pObj); + int nTag = [pCell tag]; + mpController->changePropertyWithIntValue( nTag ); + } + } + else if( [pSender isMemberOfClass: [NSTextField class]] ) + { + NSTextField* pField = static_cast(pSender); + int nTag = [pField tag]; + OUString aValue = GetOUString( [pSender stringValue] ); + mpController->changePropertyWithStringValue( nTag, aValue ); + } + else + { + SAL_INFO( "vcl.osx.print", "Unsupported class" << + ( [pSender class] ? [NSStringFromClass([pSender class]) UTF8String] : "nil" ) ); + } + mpController->updateEnableState(); +} + +-(void)triggeredNumeric:(id)pSender +{ + if( [pSender isMemberOfClass: [NSTextField class]] ) + { + NSTextField* pField = static_cast(pSender); + int nTag = [pField tag]; + sal_Int64 nValue = [pField intValue]; + + NSView* pOther = mpController->getPair( pField ); + if( pOther ) + [static_cast(pOther) setIntValue: nValue]; + + mpController->changePropertyWithIntValue( nTag, nValue ); + } + else if( [pSender isMemberOfClass: [NSStepper class]] ) + { + NSStepper* pStep = static_cast(pSender); + int nTag = [pStep tag]; + sal_Int64 nValue = [pStep intValue]; + + NSView* pOther = mpController->getPair( pStep ); + if( pOther ) + [static_cast(pOther) setIntValue: nValue]; + + mpController->changePropertyWithIntValue( nTag, nValue ); + } + else + { + SAL_INFO( "vcl.osx.print", "Unsupported class" << + ([pSender class] ? [NSStringFromClass([pSender class]) UTF8String] : "nil") ); + } + mpController->updateEnableState(); +} + +-(void)dealloc +{ + delete mpController; + [super dealloc]; +} + +@end + +namespace { + +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* pNSView, 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 = [pNSView subviews]; + unsigned int nViews = [pSubViews count]; + NSRect aUnion = NSZeroRect; + + // 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; + [pNSView 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 = static_cast([pTabbedViews objectAtIndex: i]); + NSView* pNSView = [pItem view]; + if( pNSView ) + { + NSRect aRect = [pNSView frame]; + double nDiff = aTabSize.height - aRect.size.height; + aRect.size = aTabSize; + [pNSView setFrame: aRect]; + + NSArray* pSubViews = [pNSView 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 OUString& i_rText ) +{ + NSString* pText = CreateNSString( i_rText ); + NSRect aTextRect = { NSZeroPoint, {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 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().GetLanguageTag().getLocale(), + i18n::WordType::ANYWORD_IGNOREWHITESPACES, + true ); + nRet = aBoundary.endPos; + } + return nRet; +} + +static void linebreakCell( NSCell* pBtn, const 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 ) + { + OUStringBuffer aBuf( i_rText ); + aBuf[nIndex] = '\n'; + pText = CreateNSString( aBuf.makeStringAndClear() ); + [pBtn setTitle: pText]; + [pText release]; + } + } +} + +static void addSubgroup( NSView* pCurParent, long& rCurY, const OUString& rText ) +{ + NSControl* pTextView = createLabel( rText ); + [pCurParent addSubview: [pTextView autorelease]]; + NSRect aTextRect = [pTextView frame]; + // move to nCurY + aTextRect.origin.y = rCurY - 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 + rCurY = aTextRect.origin.y - 5; +} + +static void addBool( NSView* pCurParent, long rCurX, long& rCurY, long nAttachOffset, + const OUString& rText, bool bEnabled, + const OUString& rProperty, bool bValue, + std::vector& rRightColumn, + ControllerProperties* pControllerProperties, + ControlTarget* pCtrlTarget + ) +{ + NSRect aCheckRect = { { static_cast(rCurX + nAttachOffset), 0 }, { 0, 15 } }; + NSButton* pBtn = [[NSButton alloc] initWithFrame: aCheckRect]; + [pBtn setButtonType: NSButtonTypeSwitch]; + [pBtn setState: bValue ? NSControlStateValueOn : NSControlStateValueOff]; + if( ! bEnabled ) + [pBtn setEnabled: NO]; + linebreakCell( [pBtn cell], rText ); + [pBtn sizeToFit]; + + rRightColumn.push_back( ColumnItem( pBtn ) ); + + // connect target + [pBtn setTarget: pCtrlTarget]; + [pBtn setAction: @selector(triggered:)]; + int nTag = pControllerProperties->addNameTag( rProperty ); + pControllerProperties->addObservedControl( pBtn ); + [pBtn setTag: nTag]; + + aCheckRect = [pBtn frame]; + // #i115837# add a murphy factor; it can apparently occasionally happen + // that sizeToFit does not a perfect job and that the button linebreaks again + // if - and only if - there is already a '\n' contained in the text and the width + // is minimally of + aCheckRect.size.width += 1; + + // move to rCurY + aCheckRect.origin.y = rCurY - aCheckRect.size.height; + [pBtn setFrame: aCheckRect]; + + [pCurParent addSubview: [pBtn autorelease]]; + + // update rCurY + rCurY = aCheckRect.origin.y - 5; +} + +static void addRadio( NSView* pCurParent, long rCurX, long& rCurY, long nAttachOffset, + const OUString& rText, + const OUString& rProperty, Sequence const & rChoices, sal_Int32 nSelectValue, + std::vector& rLeftColumn, + std::vector& rRightColumn, + ControllerProperties* pControllerProperties, + ControlTarget* pCtrlTarget + ) +{ + sal_Int32 nOff = 0; + if( rText.getLength() ) + { + // add a label + NSControl* pTextView = createLabel( rText ); + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = rCurX + nAttachOffset; + [pCurParent addSubview: [pTextView autorelease]]; + + rLeftColumn.push_back( ColumnItem( pTextView ) ); + + // move to nCurY + aTextRect.origin.y = rCurY - aTextRect.size.height; + [pTextView setFrame: aTextRect]; + + // update nCurY + rCurY = aTextRect.origin.y - 5; + + // indent the radio group relative to the text + // nOff = 20; + } + + // setup radio matrix + NSButtonCell* pProto = [[NSButtonCell alloc] init]; + + NSRect aRadioRect = { { static_cast(rCurX + nOff), 0 }, + { static_cast(280 - rCurX), + static_cast(5*rChoices.getLength()) } }; + [pProto setTitle: @"RadioButtonGroup"]; + [pProto setButtonType: NSButtonTypeRadio]; + NSMatrix* pMatrix = [[NSMatrix alloc] initWithFrame: aRadioRect + mode: NSRadioModeMatrix + prototype: static_cast(pProto) + numberOfRows: rChoices.getLength() + numberOfColumns: 1]; + // set individual titles + NSArray* pCells = [pMatrix cells]; + for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) + { + NSCell* pCell = [pCells objectAtIndex: m]; + linebreakCell( pCell, filterAccelerator( rChoices[m] ) ); + // connect target and action + [pCell setTarget: pCtrlTarget]; + [pCell setAction: @selector(triggered:)]; + int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); + pControllerProperties->addObservedControl( pCell ); + [pCell setTag: nTag]; + // set current selection + if( nSelectValue == m ) + [pMatrix selectCellAtRow: m column: 0]; + } + [pMatrix sizeToFit]; + aRadioRect = [pMatrix frame]; + + // move it down, so it comes to the correct position + aRadioRect.origin.y = rCurY - aRadioRect.size.height; + [pMatrix setFrame: aRadioRect]; + [pCurParent addSubview: [pMatrix autorelease]]; + + rRightColumn.push_back( ColumnItem( pMatrix ) ); + + // update nCurY + rCurY = aRadioRect.origin.y - 5; + + [pProto release]; +} + +static void addList( NSView* pCurParent, long& rCurX, long& rCurY, long /*nAttachOffset*/, + const OUString& rText, + const OUString& rProperty, Sequence const & rChoices, sal_Int32 nSelectValue, + std::vector& rLeftColumn, + std::vector& rRightColumn, + ControllerProperties* pControllerProperties, + ControlTarget* pCtrlTarget + ) +{ + // don't indent attached lists, looks bad in the existing cases + NSControl* pTextView = createLabel( rText ); + [pCurParent addSubview: [pTextView autorelease]]; + rLeftColumn.push_back( ColumnItem( pTextView ) ); + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = rCurX /* + nAttachOffset*/; + + // don't indent attached lists, looks bad in the existing cases + NSRect aBtnRect = { { rCurX /*+ nAttachOffset*/ + aTextRect.size.width, 0 }, { 0, 15 } }; + NSPopUpButton* pBtn = [[NSPopUpButton alloc] initWithFrame: aBtnRect pullsDown: NO]; + + // iterate options + for( sal_Int32 m = 0; m < rChoices.getLength(); m++ ) + { + NSString* pItemText = CreateNSString( rChoices[m] ); + [pBtn addItemWithTitle: pItemText]; + NSMenuItem* pItem = [pBtn itemWithTitle: pItemText]; + int nTag = pControllerProperties->addNameAndValueTag( rProperty, m ); + [pItem setTag: nTag]; + [pItemText release]; + } + + [pBtn selectItemAtIndex: nSelectValue]; + + // 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( rProperty )]; + + [pBtn sizeToFit]; + [pCurParent addSubview: [pBtn autorelease]]; + + rRightColumn.push_back( ColumnItem( pBtn ) ); + + // connect target and action + [pBtn setTarget: pCtrlTarget]; + [pBtn setAction: @selector(triggered:)]; + + // move to nCurY + aBtnRect = [pBtn frame]; + aBtnRect.origin.y = rCurY - 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 rCurY + rCurY = aBtnRect.origin.y - 5; +} + +static void addEdit( NSView* pCurParent, long rCurX, long& rCurY, long nAttachOffset, + const OUString& rCtrlType, + const OUString& rText, + const OUString& rProperty, const PropertyValue* pValue, + sal_Int64 nMinValue, sal_Int64 nMaxValue, + std::vector& rLeftColumn, + std::vector& rRightColumn, + ControllerProperties* pControllerProperties, + ControlTarget* pCtrlTarget + ) +{ + sal_Int32 nOff = 0; + if( rText.getLength() ) + { + // add a label + NSControl* pTextView = createLabel( rText ); + [pCurParent addSubview: [pTextView autorelease]]; + + rLeftColumn.push_back( ColumnItem( pTextView ) ); + + // move to nCurY + NSRect aTextRect = [pTextView frame]; + aTextRect.origin.x = rCurX + nAttachOffset; + aTextRect.origin.y = rCurY - aTextRect.size.height; + [pTextView setFrame: aTextRect]; + + // update nCurY + rCurY = aTextRect.origin.y - 5; + + // and set the offset for the real edit field + nOff = aTextRect.size.width + 5; + } + + NSRect aFieldRect = { { static_cast(rCurX + 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]]; + + rRightColumn.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( rProperty ); + [pFieldView setTag: nTag]; + // pControllerProperties->addNamedView( pFieldView, aPropertyName ); + + // move to nCurY + aFieldRect.origin.y = rCurY - aFieldRect.size.height; + [pFieldView setFrame: aFieldRect]; + + if( rCtrlType == "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]]; + + rRightColumn.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( pValue && pValue->Value.hasValue() ) + pValue->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( pValue && pValue->Value.hasValue() ) + { + OUString aValue; + pValue->Value >>= aValue; + if( aValue.getLength() ) + { + NSString* pText = CreateNSString( aValue ); + [pFieldView setStringValue: pText]; + [pText release]; + } + } + } + + // update nCurY + rCurY = aFieldRect.origin.y - 5; +} + +@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; + + NSRect aViewFrame = { NSZeroPoint, { 600, 400 } }; + NSRect aTabViewFrame = aViewFrame; + + NSView* pAccessoryView = [[NSView alloc] initWithFrame: aViewFrame]; + NSTabView* pTabView = [[NSTabView alloc] initWithFrame: aTabViewFrame]; + [pAccessoryView addSubview: [pTabView autorelease]]; + + // create the accessory controller + AquaPrintPanelAccessoryController* pAccessoryController = + [[AquaPrintPanelAccessoryController alloc] initWithNibName: nil bundle: nil]; + [pAccessoryController setView: [pAccessoryView autorelease]]; + [pAccessoryController forPrintOperation: pOp]; + [pAccessoryController withPrinterController: pController]; + [pAccessoryController withViewState: pState]; + + NSView* pCurParent = nullptr; + long nCurY = 0; + long nCurX = 0; + NSSize aMaxTabSize = NSZeroSize; + + ControllerProperties* pControllerProperties = new ControllerProperties( pAccessoryController ); + ControlTarget* pCtrlTarget = [[ControlTarget alloc] initWithControllerMap: pControllerProperties]; + + std::vector< ColumnItem > aLeftColumn, aRightColumn; + + // ugly: + // prepend a "selection" checkbox if the properties have such a selection in PrintContent + bool bAddSelectionCheckBox = false, bSelectionBoxEnabled = false, bSelectionBoxChecked = false; + + for( const PropertyValue & prop : rOptions ) + { + Sequence< beans::PropertyValue > aOptProp; + prop.Value >>= aOptProp; + + OUString aCtrlType; + OUString aPropertyName; + Sequence< OUString > aChoices; + Sequence< sal_Bool > aChoicesDisabled; + sal_Int32 aSelectionChecked = 0; + for( const beans::PropertyValue& rEntry : aOptProp ) + { + if( rEntry.Name == "ControlType" ) + { + rEntry.Value >>= aCtrlType; + } + else if( rEntry.Name == "Choices" ) + { + rEntry.Value >>= aChoices; + } + else if( rEntry.Name == "ChoicesDisabled" ) + { + rEntry.Value >>= aChoicesDisabled; + } + else if( rEntry.Name == "Property" ) + { + PropertyValue aVal; + rEntry.Value >>= aVal; + aPropertyName = aVal.Name; + if( aPropertyName == "PrintContent" ) + aVal.Value >>= aSelectionChecked; + } + } + if( aCtrlType == "Radio" && + aPropertyName == "PrintContent" && + aChoices.getLength() > 2 ) + { + bAddSelectionCheckBox = true; + bSelectionBoxEnabled = aChoicesDisabled.getLength() < 2 || ! aChoicesDisabled[2]; + bSelectionBoxChecked = (aSelectionChecked==2); + break; + } + } + + for( const PropertyValue & prop : rOptions ) + { + Sequence< beans::PropertyValue > aOptProp; + prop.Value >>= aOptProp; + + // extract ui element + OUString aCtrlType; + OUString aText; + OUString aPropertyName; + OUString aGroupHint; + Sequence< OUString > aChoices; + bool bEnabled = true; + sal_Int64 nMinValue = 0, nMaxValue = 0; + long nAttachOffset = 0; + bool bIgnore = false; + + for( const beans::PropertyValue& rEntry : aOptProp ) + { + if( rEntry.Name == "Text" ) + { + rEntry.Value >>= aText; + aText = filterAccelerator( aText ); + } + else if( rEntry.Name == "ControlType" ) + { + rEntry.Value >>= aCtrlType; + } + else if( rEntry.Name == "Choices" ) + { + rEntry.Value >>= aChoices; + } + else if( rEntry.Name == "Property" ) + { + PropertyValue aVal; + rEntry.Value >>= aVal; + aPropertyName = aVal.Name; + } + else if( rEntry.Name == "Enabled" ) + { + bool bValue = true; + rEntry.Value >>= bValue; + bEnabled = bValue; + } + else if( rEntry.Name == "MinValue" ) + { + rEntry.Value >>= nMinValue; + } + else if( rEntry.Name == "MaxValue" ) + { + rEntry.Value >>= nMaxValue; + } + else if( rEntry.Name == "AttachToDependency" ) + { + nAttachOffset = 20; + } + else if( rEntry.Name == "InternalUIOnly" ) + { + bool bValue = false; + rEntry.Value >>= bValue; + bIgnore = bValue; + } + else if( rEntry.Name == "GroupingHint" ) + { + rEntry.Value >>= aGroupHint; + } + } + + if( aCtrlType == "Group" || + aCtrlType == "Subgroup" || + aCtrlType == "Radio" || + aCtrlType == "List" || + aCtrlType == "Edit" || + aCtrlType == "Range" || + aCtrlType == "Bool" ) + { + bool bIgnoreSubgroup = false; + + // with `setAccessoryView' method only one accessory view can be set + // so create this single accessory view as tabbed for grouping + if( aCtrlType == "Group" + || ! pCurParent + || ( aCtrlType == "Subgroup" && nCurY < -250 && ! bIgnore ) + ) + { + OUString aGroupTitle( aText ); + if( aCtrlType == "Subgroup" ) + aGroupTitle = ControllerProperties::getMoreString(); + + // set size of current parent + if( pCurParent ) + adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); + + // new tab item + if( ! aText.getLength() ) + aText = "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]; + + nCurX = 20; // reset indent + nCurY = 0; // reset Y + // clear columns + aLeftColumn.clear(); + aRightColumn.clear(); + + if( bAddSelectionCheckBox ) + { + addBool( pCurParent, nCurX, nCurY, 0, + ControllerProperties::getPrintSelectionString(), bSelectionBoxEnabled, + "PrintContent", bSelectionBoxChecked, + aRightColumn, pControllerProperties, pCtrlTarget ); + bAddSelectionCheckBox = false; + } + } + + if( aCtrlType == "Subgroup" && pCurParent ) + { + bIgnoreSubgroup = bIgnore; + if( bIgnore ) + continue; + + addSubgroup( pCurParent, nCurY, aText ); + } + else if( bIgnoreSubgroup || bIgnore ) + { + continue; + } + else if( aCtrlType == "Bool" && pCurParent ) + { + bool bVal = false; + PropertyValue* pVal = pController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + addBool( pCurParent, nCurX, nCurY, nAttachOffset, + aText, true, aPropertyName, bVal, + aRightColumn, pControllerProperties, pCtrlTarget ); + } + else if( aCtrlType == "Radio" && pCurParent ) + { + // get currently selected value + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = pController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + + addRadio( pCurParent, nCurX, nCurY, nAttachOffset, + aText, aPropertyName, aChoices, nSelectVal, + aLeftColumn, aRightColumn, + pControllerProperties, pCtrlTarget ); + } + else if( aCtrlType == "List" && pCurParent ) + { + PropertyValue* pVal = pController->getValue( aPropertyName ); + sal_Int32 aSelectVal = 0; + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= aSelectVal; + + addList( pCurParent, nCurX, nCurY, nAttachOffset, + aText, aPropertyName, aChoices, aSelectVal, + aLeftColumn, aRightColumn, + pControllerProperties, pCtrlTarget ); + } + else if( (aCtrlType == "Edit" + || aCtrlType == "Range") && pCurParent ) + { + // current value + PropertyValue* pVal = pController->getValue( aPropertyName ); + addEdit( pCurParent, nCurX, nCurY, nAttachOffset, + aCtrlType, aText, aPropertyName, pVal, + nMinValue, nMaxValue, + aLeftColumn, aRightColumn, + pControllerProperties, pCtrlTarget ); + } + } + else + { + SAL_INFO( "vcl.osx.print", "Unsupported UI option \"" << aCtrlType << "\""); + } + } + + pControllerProperties->updateEnableState(); + adjustViewAndChildren( pCurParent, aMaxTabSize, aLeftColumn, aRightColumn ); + + // 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]; + + // get the print panel + NSPrintPanel* pPrintPanel = [pOp printPanel]; + [pPrintPanel setOptions: [pPrintPanel options] | NSPrintPanelShowsPreview]; + // add the accessory controller to the panel + [pPrintPanel addAccessoryController: [pAccessoryController autorelease]]; + + // set the current selected tab item + if( pState->nLastPage >= 0 && pState->nLastPage < [pTabView numberOfTabViewItems] ) + [pTabView selectTabViewItemAtIndex: pState->nLastPage]; + + return pCtrlTarget; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/printview.mm b/vcl/osx/printview.mm new file mode 100644 index 000000000..b54e1b056 --- /dev/null +++ b/vcl/osx/printview.mm @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include +#include + +@implementation AquaPrintView + +-(id)initWithController: (vcl::PrinterController*)pController + withInfoPrinter: (AquaSalInfoPrinter*)pInfoPrinter +{ + NSRect aRect = { NSZeroPoint, [pInfoPrinter->getPrintInfo() paperSize] }; + if( (self = [super initWithFrame: aRect]) != nil ) + { + mpController = pController; + mpInfoPrinter = pInfoPrinter; + } + return self; +} + +-(BOOL)knowsPageRange: (NSRangePointer)range +{ + range->location = 1; + range->length = mpInfoPrinter->getCurPageRangeCount(); + return YES; +} + +-(NSRect)rectForPage: (int)page +{ + NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize]; + int nWidth = static_cast(aPaperSize.width); + // #i101108# sanity check + if( nWidth < 1 ) + nWidth = 1; + NSRect aRect = { { static_cast(page % nWidth), + static_cast(page / nWidth) }, + aPaperSize }; + return aRect; +} + +-(NSPoint)locationOfPrintRect: (NSRect)aRect +{ + (void)aRect; + return NSZeroPoint; +} + +-(void)drawRect: (NSRect)rect +{ + mpInfoPrinter->setStartPageOffset( static_cast(rect.origin.x), + static_cast(rect.origin.y) ); + NSSize aPaperSize = [mpInfoPrinter->getPrintInfo() paperSize]; + int nPage = static_cast(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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/res/MainMenu.nib/classes.nib b/vcl/osx/res/MainMenu.nib/classes.nib new file mode 100644 index 000000000..b9b4b09f6 --- /dev/null +++ b/vcl/osx/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/osx/res/MainMenu.nib/info.nib b/vcl/osx/res/MainMenu.nib/info.nib new file mode 100644 index 000000000..856429aee --- /dev/null +++ b/vcl/osx/res/MainMenu.nib/info.nib @@ -0,0 +1,21 @@ + + + + + IBDocumentLocation + 135 107 356 240 0 0 1680 1028 + IBEditorPositions + + 29 + 132 352 141 44 0 0 1680 1028 + + IBFramework Version + 446.1 + IBOpenObjects + + 29 + + IBSystem Version + 8R2218 + + diff --git a/vcl/osx/res/MainMenu.nib/keyedobjects.nib b/vcl/osx/res/MainMenu.nib/keyedobjects.nib new file mode 100644 index 000000000..d39d10119 Binary files /dev/null and b/vcl/osx/res/MainMenu.nib/keyedobjects.nib differ diff --git a/vcl/osx/saldata.cxx b/vcl/osx/saldata.cxx new file mode 100644 index 000000000..5235f657f --- /dev/null +++ b/vcl/osx/saldata.cxx @@ -0,0 +1,298 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#import "apple_remote/RemoteMainController.h" + +oslThreadKey SalData::s_aAutoReleaseKey = nullptr; + +static void releasePool( void* pPool ) +{ + if( pPool ) + [static_cast(pPool) release]; +} + +SalData::SalData() +: + mpTimerProc( nullptr ), + mpInstance( nullptr ), + mpFirstObject( nullptr ), + mpFirstVD( nullptr ), + mpFirstPrinter( nullptr ), + mpFontList( nullptr ), + mpStatusItem( nil ), + mxRGBSpace( CGColorSpaceCreateWithName(kCGColorSpaceSRGB) ), + mxGraySpace( CGColorSpaceCreateWithName(kCGColorSpaceGenericGrayGamma2_2) ), + maCursors(), + mbIsScrollbarDoubleMax( false ), +#if !HAVE_FEATURE_MACOSX_SANDBOX + mpAppleRemoteMainController( nullptr ), +#endif + mpDockIconClickHandler( nil ), + mnDPIX( 0 ), + mnDPIY( 0 ) +{ + SetSalData(this); + maCursors.fill( INVALID_CURSOR_PTR ); + if( s_aAutoReleaseKey == nullptr ) + s_aAutoReleaseKey = osl_createThreadKey( releasePool ); +} + +SalData::~SalData() +{ + CGColorSpaceRelease( mxRGBSpace ); + CGColorSpaceRelease( mxGraySpace ); + for( NSCursor* pCurs : maCursors ) + { + if( pCurs && pCurs != INVALID_CURSOR_PTR ) + [pCurs release]; + } + if( s_aAutoReleaseKey ) + { + // release the last pool + NSAutoreleasePool* pPool = reinterpret_cast( osl_getThreadKeyData( s_aAutoReleaseKey ) ); + if( pPool ) + { + osl_setThreadKeyData( s_aAutoReleaseKey, nullptr ); + [pPool release]; + } + + osl_destroyThreadKey( s_aAutoReleaseKey ); + s_aAutoReleaseKey = nullptr; + } +#if !HAVE_FEATURE_MACOSX_SANDBOX + if ( mpAppleRemoteMainController ) + [mpAppleRemoteMainController release]; +#endif + + if( mpStatusItem ) + { + [mpStatusItem release]; + mpStatusItem = nil; + } + SetSalData( nullptr ); +} + +void SalData::ensureThreadAutoreleasePool() +{ + NSAutoreleasePool* pPool = nil; + if( s_aAutoReleaseKey ) + { + pPool = reinterpret_cast( osl_getThreadKeyData( s_aAutoReleaseKey ) ); + if( ! pPool ) + { + pPool = [[NSAutoreleasePool alloc] init]; + osl_setThreadKeyData( s_aAutoReleaseKey, pPool ); + } + } + else + { + OSL_FAIL( "no autorelease key" ); + } +} + +namespace { + +NSImage* load_icon_by_name(const OUString& rIconName) +{ + OUString sIconTheme = Application::GetSettings().GetStyleSettings().DetermineIconTheme(); + OUString sUILang = Application::GetSettings().GetUILanguageTag().getBcp47(); + auto xMemStm = ImageTree::get().getImageStream(rIconName, sIconTheme, sUILang); + if (!xMemStm) + return nullptr; + + auto data = xMemStm->GetData(); + auto length = xMemStm->TellEnd(); + NSData * byteData = [NSData dataWithBytes:data length:length]; + NSBitmapImageRep * imageRep = [NSBitmapImageRep imageRepWithData:byteData]; + NSSize imageSize = NSMakeSize(CGImageGetWidth([imageRep CGImage]), CGImageGetHeight([imageRep CGImage])); + + NSImage * image = [[NSImage alloc] initWithSize:imageSize]; + [image addRepresentation:imageRep]; + return image; +} + +} + +#define MAKE_CURSOR( vcl_name, name, name2 ) \ + case vcl_name: \ + aHotSpot = NSPoint{name##curs_x_hot, name##curs_y_hot}; \ + aIconName = name2; \ + break + +NSCursor* SalData::getCursor( PointerStyle i_eStyle ) +{ + NSCursor* pCurs = maCursors[ i_eStyle ]; + if( pCurs != INVALID_CURSOR_PTR ) + return pCurs; + + NSPoint aHotSpot; + OUString aIconName; + + switch( i_eStyle ) + { + // TODO + MAKE_CURSOR( PointerStyle::Wait, wait_, RID_CURSOR_WAIT ); + MAKE_CURSOR( PointerStyle::NWSize, nwsize_, RID_CURSOR_NWSIZE ); + MAKE_CURSOR( PointerStyle::NESize, nesize_, RID_CURSOR_NESIZE ); + MAKE_CURSOR( PointerStyle::SWSize, swsize_, RID_CURSOR_SWSIZE ); + MAKE_CURSOR( PointerStyle::SESize, sesize_, RID_CURSOR_SESIZE ); + MAKE_CURSOR( PointerStyle::WindowNWSize, window_nwsize_, RID_CURSOR_WINDOW_NWSIZE ); + MAKE_CURSOR( PointerStyle::WindowNESize, window_nesize_, RID_CURSOR_WINDOW_NESIZE ); + MAKE_CURSOR( PointerStyle::WindowSWSize, window_swsize_, RID_CURSOR_WINDOW_SWSIZE ); + MAKE_CURSOR( PointerStyle::WindowSESize, window_sesize_, RID_CURSOR_WINDOW_SESIZE ); + + MAKE_CURSOR( PointerStyle::Help, help_, RID_CURSOR_HELP ); + MAKE_CURSOR( PointerStyle::Pen, pen_, RID_CURSOR_PEN ); + MAKE_CURSOR( PointerStyle::Null, null, RID_CURSOR_NULL ); + MAKE_CURSOR( PointerStyle::Magnify, magnify_, RID_CURSOR_MAGNIFY ); + MAKE_CURSOR( PointerStyle::Fill, fill_, RID_CURSOR_FILL ); + MAKE_CURSOR( PointerStyle::MoveData, movedata_, RID_CURSOR_MOVE_DATA ); + MAKE_CURSOR( PointerStyle::CopyData, copydata_, RID_CURSOR_COPY_DATA ); + MAKE_CURSOR( PointerStyle::MoveFile, movefile_, RID_CURSOR_MOVE_FILE ); + MAKE_CURSOR( PointerStyle::CopyFile, copyfile_, RID_CURSOR_COPY_FILE ); + MAKE_CURSOR( PointerStyle::MoveFiles, movefiles_, RID_CURSOR_MOVE_FILES ); + MAKE_CURSOR( PointerStyle::CopyFiles, copyfiles_, RID_CURSOR_COPY_FILES ); + MAKE_CURSOR( PointerStyle::NotAllowed, nodrop_, RID_CURSOR_NOT_ALLOWED ); + MAKE_CURSOR( PointerStyle::Rotate, rotate_, RID_CURSOR_ROTATE ); + MAKE_CURSOR( PointerStyle::HShear, hshear_, RID_CURSOR_H_SHEAR ); + MAKE_CURSOR( PointerStyle::VShear, vshear_, RID_CURSOR_V_SHEAR ); + MAKE_CURSOR( PointerStyle::DrawLine, drawline_, RID_CURSOR_DRAW_LINE ); + MAKE_CURSOR( PointerStyle::DrawRect, drawrect_, RID_CURSOR_DRAW_RECT ); + MAKE_CURSOR( PointerStyle::DrawPolygon, drawpolygon_, RID_CURSOR_DRAW_POLYGON ); + MAKE_CURSOR( PointerStyle::DrawBezier, drawbezier_, RID_CURSOR_DRAW_BEZIER ); + MAKE_CURSOR( PointerStyle::DrawArc, drawarc_, RID_CURSOR_DRAW_ARC ); + MAKE_CURSOR( PointerStyle::DrawPie, drawpie_, RID_CURSOR_DRAW_PIE ); + MAKE_CURSOR( PointerStyle::DrawCircleCut, drawcirclecut_, RID_CURSOR_DRAW_CIRCLE_CUT ); + MAKE_CURSOR( PointerStyle::DrawEllipse, drawellipse_, RID_CURSOR_DRAW_ELLIPSE ); + MAKE_CURSOR( PointerStyle::DrawConnect, drawconnect_, RID_CURSOR_DRAW_CONNECT ); + MAKE_CURSOR( PointerStyle::DrawText, drawtext_, RID_CURSOR_DRAW_TEXT ); + MAKE_CURSOR( PointerStyle::Mirror, mirror_, RID_CURSOR_MIRROR ); + MAKE_CURSOR( PointerStyle::Crook, crook_, RID_CURSOR_CROOK ); + MAKE_CURSOR( PointerStyle::Crop, crop_, RID_CURSOR_CROP ); + MAKE_CURSOR( PointerStyle::MovePoint, movepoint_, RID_CURSOR_MOVE_POINT ); + MAKE_CURSOR( PointerStyle::MoveBezierWeight, movebezierweight_, RID_CURSOR_MOVE_BEZIER_WEIGHT ); + MAKE_CURSOR( PointerStyle::DrawFreehand, drawfreehand_, RID_CURSOR_DRAW_FREEHAND ); + MAKE_CURSOR( PointerStyle::DrawCaption, drawcaption_, RID_CURSOR_DRAW_CAPTION ); + MAKE_CURSOR( PointerStyle::LinkData, linkdata_, RID_CURSOR_LINK_DATA ); + MAKE_CURSOR( PointerStyle::MoveDataLink, movedlnk_, RID_CURSOR_MOVE_DATA_LINK ); + MAKE_CURSOR( PointerStyle::CopyDataLink, copydlnk_, RID_CURSOR_COPY_DATA_LINK ); + MAKE_CURSOR( PointerStyle::LinkFile, linkfile_, RID_CURSOR_LINK_FILE ); + MAKE_CURSOR( PointerStyle::MoveFileLink, moveflnk_, RID_CURSOR_MOVE_FILE_LINK ); + MAKE_CURSOR( PointerStyle::CopyFileLink, copyflnk_, RID_CURSOR_COPY_FILE_LINK ); + MAKE_CURSOR( PointerStyle::Chart, chart_, RID_CURSOR_CHART ); + MAKE_CURSOR( PointerStyle::Detective, detective_, RID_CURSOR_DETECTIVE ); + MAKE_CURSOR( PointerStyle::PivotCol, pivotcol_, RID_CURSOR_PIVOT_COLUMN ); + MAKE_CURSOR( PointerStyle::PivotRow, pivotrow_, RID_CURSOR_PIVOT_ROW ); + MAKE_CURSOR( PointerStyle::PivotField, pivotfld_, RID_CURSOR_PIVOT_FIELD ); + MAKE_CURSOR( PointerStyle::PivotDelete, pivotdel_, RID_CURSOR_PIVOT_DELETE ); + MAKE_CURSOR( PointerStyle::Chain, chain_, RID_CURSOR_CHAIN ); + MAKE_CURSOR( PointerStyle::ChainNotAllowed, chainnot_, RID_CURSOR_CHAIN_NOT_ALLOWED ); + MAKE_CURSOR( PointerStyle::AutoScrollN, asn_, RID_CURSOR_AUTOSCROLL_N ); + MAKE_CURSOR( PointerStyle::AutoScrollS, ass_, RID_CURSOR_AUTOSCROLL_S ); + MAKE_CURSOR( PointerStyle::AutoScrollW, asw_, RID_CURSOR_AUTOSCROLL_W ); + MAKE_CURSOR( PointerStyle::AutoScrollE, ase_, RID_CURSOR_AUTOSCROLL_E ); + MAKE_CURSOR( PointerStyle::AutoScrollNW, asnw_, RID_CURSOR_AUTOSCROLL_NW ); + MAKE_CURSOR( PointerStyle::AutoScrollNE, asne_, RID_CURSOR_AUTOSCROLL_NE ); + MAKE_CURSOR( PointerStyle::AutoScrollSW, assw_, RID_CURSOR_AUTOSCROLL_SW ); + MAKE_CURSOR( PointerStyle::AutoScrollSE, asse_, RID_CURSOR_AUTOSCROLL_SE ); + MAKE_CURSOR( PointerStyle::AutoScrollNS, asns_, RID_CURSOR_AUTOSCROLL_NS ); + MAKE_CURSOR( PointerStyle::AutoScrollWE, aswe_, RID_CURSOR_AUTOSCROLL_WE ); + MAKE_CURSOR( PointerStyle::AutoScrollNSWE, asnswe_, RID_CURSOR_AUTOSCROLL_NSWE ); + MAKE_CURSOR( PointerStyle::TextVertical, vertcurs_, RID_CURSOR_TEXT_VERTICAL ); + + // #i32329# + MAKE_CURSOR( PointerStyle::TabSelectS, tblsels_, RID_CURSOR_TAB_SELECT_S ); + MAKE_CURSOR( PointerStyle::TabSelectE, tblsele_, RID_CURSOR_TAB_SELECT_E ); + MAKE_CURSOR( PointerStyle::TabSelectSE, tblselse_, RID_CURSOR_TAB_SELECT_SE ); + MAKE_CURSOR( PointerStyle::TabSelectW, tblselw_, RID_CURSOR_TAB_SELECT_W ); + MAKE_CURSOR( PointerStyle::TabSelectSW, tblselsw_, RID_CURSOR_TAB_SELECT_SW ); + + MAKE_CURSOR( PointerStyle::HideWhitespace, hidewhitespace_, RID_CURSOR_HIDE_WHITESPACE ); + MAKE_CURSOR( PointerStyle::ShowWhitespace, showwhitespace_, RID_CURSOR_SHOW_WHITESPACE ); + + default: + SAL_WARN( "vcl", "pointer style " << static_cast(i_eStyle) << "not implemented" ); + assert( false && "pointer style not implemented" ); + break; + } + + NSImage* theImage = load_icon_by_name(aIconName); + assert ([theImage size].width == 128 || [theImage size].width == 32); + if ([theImage size].width == 128) + { + // If we have a 128x128 image, generate scaled versions of it. + // This will result in macOS picking a reasonably sized image for different screen dpi. + NSSize cursorSize = NSMakeSize(32,32); + NSImage *multiResImage = [[NSImage alloc] initWithSize:cursorSize]; + for (int scale = 1; scale <= 4; scale++) { + NSAffineTransform *xform = [[NSAffineTransform alloc] init]; + [xform scaleBy:scale]; + id hints = @{ NSImageHintCTM: xform }; + CGImageRef rasterCGImage = [theImage CGImageForProposedRect:nullptr context:nil hints:hints]; + NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:rasterCGImage]; + [rep setSize:cursorSize]; + [multiResImage addRepresentation:rep]; + } + pCurs = [[NSCursor alloc] initWithImage: multiResImage hotSpot: aHotSpot]; + } + else + pCurs = [[NSCursor alloc] initWithImage: theImage hotSpot: aHotSpot]; + + 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]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'setView:' is deprecated: first deprecated in macOS 10.14 - Use the standard + // button property instead" + [pData->mpStatusItem setView: pView ]; +SAL_WNODEPRECATED_DECLARATIONS_POP + [pView display]; + } + } + return pData->mpStatusItem; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salframe.cxx b/vcl/osx/salframe.cxx new file mode 100644 index 000000000..71cc5a4f1 --- /dev/null +++ b/vcl/osx/salframe.cxx @@ -0,0 +1,1828 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +// needed for theming +// FIXME: move theming code to salnativewidgets.cxx +#include +#include + +using namespace std; + +AquaSalFrame* AquaSalFrame::s_pCaptureFrame = nullptr; + +AquaSalFrame::AquaSalFrame( SalFrame* pParent, SalFrameStyleFlags salFrameStyle ) : + mpNSWindow(nil), + mpNSView(nil), + mpDockMenuEntry(nil), + mpGraphics(nullptr), + mpParent(nullptr), + 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( nullptr ), + mnExtStyle( 0 ), + mePointerStyle( PointerStyle::Arrow ), + mnTrackingRectTag( 0 ), + mrClippingPath( nullptr ), + mnICOptions( InputContextFlags::NONE ), + mnBlinkCursorDelay ( 500 ) +{ + mpParent = dynamic_cast(pParent); + + initWindowAndView(); + + SalData* pSalData = GetSalData(); + pSalData->mpInstance->insertFrame( this ); + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + if (userDefaults != nil) + { + id setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOn"]; + if (setting) + mnBlinkCursorDelay = [setting intValue]; + else + { + setting = [userDefaults objectForKey: @"NSTextInsertionPointBlinkPeriodOff"]; + if (setting) + mnBlinkCursorDelay = [setting intValue]; + } + } +} + +AquaSalFrame::~AquaSalFrame() +{ + if (mbFullScreen) + doShowFullScreen(false, maGeometry.nDisplayScreenNumber); + + assert( GetSalData()->mpInstance->IsMainThread() ); + + // 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 + doResetClipRegion(); + + [SalFrameView unsetMouseFrame: this]; + + SalData* pSalData = GetSalData(); + pSalData->mpInstance->eraseFrame( this ); + pSalData->maPresentationFrames.remove( this ); + + SAL_WARN_IF( this == s_pCaptureFrame, "vcl", "capture frame destroyed" ); + if( this == s_pCaptureFrame ) + s_pCaptureFrame = nullptr; + + delete mpGraphics; + + if( mpDockMenuEntry ) + { + NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu(); + // life cycle comment: the menu has ownership of the item, so no release + [pDock removeItem: mpDockMenuEntry]; + if ([pDock numberOfItems] != 0 + && [[pDock itemAtIndex: 0] isSeparatorItem]) + { + [pDock removeItemAtIndex: 0]; + } + } + if ( mpNSView ) { + [AquaA11yFactory revokeView: mpNSView]; + [mpNSView release]; + } + if ( mpNSWindow ) + [mpNSWindow release]; +} + +void AquaSalFrame::initWindowAndView() +{ + OSX_SALDATA_RUNINMAIN( initWindowAndView() ) + + // initialize mirroring parameters + // FIXME: screens changing + NSScreen* pNSScreen = [mpNSWindow screen]; + if( pNSScreen == nil ) + pNSScreen = [NSScreen mainScreen]; + maScreenRect = [pNSScreen frame]; + + // calculate some default geometry + NSRect aVisibleRect = [pNSScreen visibleFrame]; + CocoaToVCL( aVisibleRect ); + + maGeometry.nX = static_cast(aVisibleRect.origin.x + aVisibleRect.size.width / 10); + maGeometry.nY = static_cast(aVisibleRect.origin.y + aVisibleRect.size.height / 10); + maGeometry.nWidth = static_cast(aVisibleRect.size.width * 0.8); + maGeometry.nHeight = static_cast(aVisibleRect.size.height * 0.8); + + // calculate style mask +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSBorderlessWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSMiniaturizableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSTitledWindowMask' is deprecated: first deprecated in macOS 10.12 + if( (mnStyle & SalFrameStyleFlags::FLOAT) || + (mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) ) + mnStyleMask = NSBorderlessWindowMask; + else if( mnStyle & SalFrameStyleFlags::DEFAULT ) + { + mnStyleMask = NSTitledWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask | + NSClosableWindowMask; + // make default window "maximized" + maGeometry.nX = static_cast(aVisibleRect.origin.x); + maGeometry.nY = static_cast(aVisibleRect.origin.y); + maGeometry.nWidth = static_cast(aVisibleRect.size.width); + maGeometry.nHeight = static_cast(aVisibleRect.size.height); + mbPositioned = mbSized = true; + } + else + { + if( mnStyle & SalFrameStyleFlags::MOVEABLE ) + { + mnStyleMask |= NSTitledWindowMask; + if( mpParent == nullptr ) + mnStyleMask |= NSMiniaturizableWindowMask; + } + if( mnStyle & SalFrameStyleFlags::SIZEABLE ) + mnStyleMask |= NSResizableWindowMask; + if( mnStyle & SalFrameStyleFlags::CLOSEABLE ) + mnStyleMask |= NSClosableWindowMask; + // documentation says anything other than NSBorderlessWindowMask (=0) + // should also include NSTitledWindowMask; + if( mnStyleMask != 0 ) + mnStyleMask |= NSTitledWindowMask; + } +SAL_WNODEPRECATED_DECLARATIONS_POP + + if (Application::IsBitmapRendering()) + return; + + // #i91990# support GUI-less (daemon) execution + @try + { + mpNSWindow = [[SalFrameWindow alloc] initWithSalFrame: this]; + mpNSView = [[SalFrameView alloc] initWithSalFrame: this]; + } + @catch ( id ) + { + std::abort(); + } + + if( mnStyle & SalFrameStyleFlags::TOOLTIP ) + [mpNSWindow setIgnoresMouseEvents: YES]; + else + [mpNSWindow setAcceptsMouseMovedEvents: YES]; + [mpNSWindow setHasShadow: YES]; + + [mpNSWindow setDelegate: static_cast >(mpNSWindow)]; + + [mpNSWindow setRestorable:NO]; + const NSRect aRect = { NSZeroPoint, NSMakeSize( maGeometry.nWidth, maGeometry.nHeight )}; + mnTrackingRectTag = [mpNSView addTrackingRect: aRect owner: mpNSView userData: nil assumeInside: NO]; + + maSysData.mpNSView = mpNSView; + + UpdateFrameGeometry(); + + [mpNSWindow setContentView: mpNSView]; +} + +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() +{ + OSX_SALDATA_RUNINMAIN( screenParametersChanged() ) + + UpdateFrameGeometry(); + + if( mpGraphics ) + mpGraphics->updateResolution(); + + if (!mbGeometryDidChange) + return; + + CallCallback( SalEvent::DisplayChanged, nullptr ); +} + +SalGraphics* AquaSalFrame::AcquireGraphics() +{ + if ( mbGraphics ) + return nullptr; + + if ( !mpGraphics ) + { + mpGraphics = new AquaSalGraphics; + mpGraphics->SetWindowGraphics( this ); + } + + mbGraphics = true; + return mpGraphics; +} + +void AquaSalFrame::ReleaseGraphics( SalGraphics *pGraphics ) +{ + SAL_WARN_IF( pGraphics != mpGraphics, "vcl", "graphics released on wrong frame" ); + mbGraphics = false; +} + +bool AquaSalFrame::PostEvent(std::unique_ptr pData) +{ + GetSalData()->mpInstance->PostEvent( this, pData.release(), SalEvent::UserEvent ); + return true; +} + +void AquaSalFrame::SetTitle(const OUString& rTitle) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( SetTitle(rTitle) ) + + // #i113170# may not be the main thread if called from UNO API + SalData::ensureThreadAutoreleasePool(); + + NSString* pTitle = CreateNSString( rTitle ); + [mpNSWindow setTitle: pTitle]; + + // create an entry in the dock menu + const SalFrameStyleFlags nAppWindowStyle = SalFrameStyleFlags::CLOSEABLE | SalFrameStyleFlags::MOVEABLE; + if( mpParent == nullptr && + (mnStyle & nAppWindowStyle) == nAppWindowStyle ) + { + if( mpDockMenuEntry == nullptr ) + { + NSMenu* pDock = AquaSalInstance::GetDynamicDockMenu(); + + if ([pDock numberOfItems] != 0) { + NSMenuItem* pTopItem = [pDock itemAtIndex: 0]; + if ( [pTopItem hasSubmenu] ) + [pDock insertItem: [NSMenuItem separatorItem] atIndex: 0]; + } + + mpDockMenuEntry = [pDock insertItemWithTitle: pTitle + action: @selector(dockMenuItemTriggered:) + keyEquivalent: @"" + atIndex: 0]; + [mpDockMenuEntry setTarget: mpNSWindow]; + + // 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( sal_uInt16 ) +{ +} + +void AquaSalFrame::SetRepresentedURL( const OUString& i_rDocURL ) +{ + OSX_SALDATA_RUNINMAIN( SetRepresentedURL( i_rDocURL ) ) + + if( comphelper::isFileUrl(i_rDocURL) ) + { + OUString aSysPath; + osl_getSystemPathFromFileURL( i_rDocURL.pData, &aSysPath.pData ); + NSString* pStr = CreateNSString( aSysPath ); + if( pStr ) + { + [pStr autorelease]; + [mpNSWindow setRepresentedFilename: pStr]; + } + } +} + +void AquaSalFrame::initShow() +{ + OSX_SALDATA_RUNINMAIN( initShow() ) + + mbInitShow = false; + if( ! mbPositioned && ! mbFullScreen ) + { + tools::Rectangle aScreenRect; + GetWorkArea( aScreenRect ); + if( mpParent ) // center relative to parent + { + // center on parent + long nNewX = mpParent->maGeometry.nX + (static_cast(mpParent->maGeometry.nWidth) - static_cast(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 + (static_cast(mpParent->maGeometry.nHeight) - static_cast(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 & SalFrameStyleFlags::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: mpNSView]; +} + +void AquaSalFrame::SendPaintEvent( const tools::Rectangle* pRect ) +{ + OSX_SALDATA_RUNINMAIN( SendPaintEvent( 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) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( Show(bVisible, bNoActivate) ) + + mbShown = bVisible; + if(bVisible) + { + if( mbInitShow ) + initShow(); + + CallCallback(SalEvent::Resize, nullptr); + // trigger filling our backbuffer + SendPaintEvent(); + + if( bNoActivate || [mpNSWindow canBecomeKeyWindow] == NO ) + [mpNSWindow orderFront: NSApp]; + else + [mpNSWindow 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 & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::FLOAT) ) ) + { + [mpParent->mpNSWindow addChildWindow: mpNSWindow ordered: NSWindowAbove]; + } + } + + if( mbPresentation ) + [mpNSWindow makeMainWindow]; + } + else + { + // if the frame holding the current menubar gets hidden + // show the default menubar + if( mpMenu && mpMenu->mbMenuBar && AquaSalMenu::pCurrentMenuBar == mpMenu ) + AquaSalMenu::setDefaultMenu(); + + // #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 && [mpNSWindow isKeyWindow] ) + [mpParent->mpNSWindow makeKeyAndOrderFront: NSApp]; + + [SalFrameView unsetMouseFrame: this]; + if( mpParent && [mpNSWindow parentWindow] == mpParent->mpNSWindow ) + [mpParent->mpNSWindow removeChildWindow: mpNSWindow]; + + [mpNSWindow orderOut: NSApp]; + } +} + +void AquaSalFrame::SetMinClientSize( long nWidth, long nHeight ) +{ + OSX_SALDATA_RUNINMAIN( SetMinClientSize( nWidth, nHeight ) ) + + mnMinWidth = nWidth; + mnMinHeight = nHeight; + + if( mpNSWindow ) + { + // Always add the decoration as the dimension concerns only + // the content rectangle + nWidth += maGeometry.nLeftDecoration + maGeometry.nRightDecoration; + nHeight += maGeometry.nTopDecoration + maGeometry.nBottomDecoration; + + NSSize aSize = { static_cast(nWidth), static_cast(nHeight) }; + + // Size of full window (content+structure) although we only + // have the client size in arguments + [mpNSWindow setMinSize: aSize]; + } +} + +void AquaSalFrame::SetMaxClientSize( long nWidth, long nHeight ) +{ + OSX_SALDATA_RUNINMAIN( SetMaxClientSize( nWidth, nHeight ) ) + + mnMaxWidth = nWidth; + mnMaxHeight = nHeight; + + if( mpNSWindow ) + { + // 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 = { static_cast(nWidth), static_cast(nHeight) }; + + // Size of full window (content+structure) although we only + // have the client size in arguments + [mpNSWindow setMaxSize: aSize]; + } +} + +void AquaSalFrame::GetClientSize( long& rWidth, long& rHeight ) +{ + if (mbShown || mbInitShow || Application::IsBitmapRendering()) + { + rWidth = maGeometry.nWidth; + rHeight = maGeometry.nHeight; + } + else + { + rWidth = 0; + rHeight = 0; + } +} + +SalEvent AquaSalFrame::PreparePosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags) +{ + SalEvent nEvent = SalEvent::NONE; + assert(mpNSWindow || Application::IsBitmapRendering()); + + 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; + } + + if (Application::IsBitmapRendering()) + { + if (nFlags & SAL_FRAME_POSSIZE_X) + maGeometry.nX = nX; + if (nFlags & SAL_FRAME_POSSIZE_Y) + maGeometry.nY = nY; + if (nFlags & SAL_FRAME_POSSIZE_WIDTH) + { + maGeometry.nWidth = nWidth; + if (mnMaxWidth > 0 && maGeometry.nWidth > o3tl::make_unsigned(mnMaxWidth)) + maGeometry.nWidth = mnMaxWidth; + if (mnMinWidth > 0 && maGeometry.nWidth < o3tl::make_unsigned(mnMinWidth)) + maGeometry.nWidth = mnMinWidth; + } + if (nFlags & SAL_FRAME_POSSIZE_HEIGHT) + { + maGeometry.nHeight = nHeight; + if (mnMaxHeight > 0 && maGeometry.nHeight > o3tl::make_unsigned(mnMaxHeight)) + maGeometry.nHeight = mnMaxHeight; + if (mnMinHeight > 0 && maGeometry.nHeight < o3tl::make_unsigned(mnMinHeight)) + maGeometry.nHeight = mnMinHeight; + } + if (nEvent != SalEvent::NONE) + CallCallback(nEvent, nullptr); + } + + return nEvent; +} + +void AquaSalFrame::SetWindowState( const SalFrameState* pState ) +{ + if (!mpNSWindow && !Application::IsBitmapRendering()) + return; + + OSX_SALDATA_RUNINMAIN( SetWindowState( pState ) ) + + sal_uInt16 nFlags = 0; + nFlags |= ((pState->mnMask & WindowStateMask::X) ? SAL_FRAME_POSSIZE_X : 0); + nFlags |= ((pState->mnMask & WindowStateMask::Y) ? SAL_FRAME_POSSIZE_Y : 0); + nFlags |= ((pState->mnMask & WindowStateMask::Width) ? SAL_FRAME_POSSIZE_WIDTH : 0); + nFlags |= ((pState->mnMask & WindowStateMask::Height) ? SAL_FRAME_POSSIZE_HEIGHT : 0); + + SalEvent nEvent = PreparePosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nFlags); + if (Application::IsBitmapRendering()) + return; + + // set normal state + NSRect aStateRect = [mpNSWindow frame]; + aStateRect = [NSWindow contentRectForFrameRect: aStateRect styleMask: mnStyleMask]; + CocoaToVCL(aStateRect); + if (pState->mnMask & WindowStateMask::X) + aStateRect.origin.x = float(pState->mnX); + if (pState->mnMask & WindowStateMask::Y) + aStateRect.origin.y = float(pState->mnY); + if (pState->mnMask & WindowStateMask::Width) + aStateRect.size.width = float(pState->mnWidth); + if (pState->mnMask & WindowStateMask::Height) + aStateRect.size.height = float(pState->mnHeight); + VCLToCocoa(aStateRect); + aStateRect = [NSWindow frameRectForContentRect: aStateRect styleMask: mnStyleMask]; + [mpNSWindow setFrame: aStateRect display: NO]; + + if (pState->mnState == WindowStateState::Minimized) + [mpNSWindow miniaturize: NSApp]; + else if ([mpNSWindow isMiniaturized]) + [mpNSWindow deminiaturize: NSApp]; + + /* ZOOMED is not really maximized (actually it toggles between a user set size and + the program specified one), but comes closest since the default behavior is + "maximized" if the user did not intervene + */ + if (pState->mnState == WindowStateState::Maximized) + { + if (![mpNSWindow isZoomed]) + [mpNSWindow zoom: NSApp]; + } + else + { + if ([mpNSWindow isZoomed]) + [mpNSWindow zoom: NSApp]; + } + + // get new geometry + UpdateFrameGeometry(); + + // send event that we were moved/sized + if( nEvent != SalEvent::NONE ) + CallCallback( nEvent, nullptr ); + + if (mbShown) + { + // trigger filling our backbuffer + SendPaintEvent(); + + // tell the system the views need to be updated + [mpNSWindow display]; + } +} + +bool AquaSalFrame::GetWindowState( SalFrameState* pState ) +{ + if (!mpNSWindow) + { + if (Application::IsBitmapRendering()) + { + pState->mnMask = WindowStateMask::X | WindowStateMask::Y + | WindowStateMask::Width | WindowStateMask::Height + | WindowStateMask::State; + pState->mnX = maGeometry.nX; + pState->mnY = maGeometry.nY; + pState->mnWidth = maGeometry.nWidth; + pState->mnHeight = maGeometry.nHeight; + pState->mnState = WindowStateState::Normal; + return true; + } + return false; + } + + OSX_SALDATA_RUNINMAIN_UNION( GetWindowState( pState ), boolean ) + + pState->mnMask = WindowStateMask::X | + WindowStateMask::Y | + WindowStateMask::Width | + WindowStateMask::Height | + WindowStateMask::State; + + NSRect aStateRect = [mpNSWindow 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); + + if( [mpNSWindow isMiniaturized] ) + pState->mnState = WindowStateState::Minimized; + else if( ! [mpNSWindow isZoomed] ) + pState->mnState = WindowStateState::Normal; + else + pState->mnState = WindowStateState::Maximized; + + return true; +} + +void AquaSalFrame::SetScreenNumber(unsigned int nScreen) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( SetScreenNumber( nScreen ) ) + + NSArray* pScreens = [NSScreen screens]; + 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 = [mpNSWindow screen]; + if( pScreen ) + { + NSRect aCurScreen = [pScreen frame]; + if( aCurScreen.origin.x != aNewScreen.origin.x || + aCurScreen.origin.y != aNewScreen.origin.y ) + { + NSRect aFrameRect = [mpNSWindow frame]; + aFrameRect.origin.x += aNewScreen.origin.x - aCurScreen.origin.x; + aFrameRect.origin.y += aNewScreen.origin.y - aCurScreen.origin.y; + [mpNSWindow setFrame: aFrameRect display: NO]; + UpdateFrameGeometry(); + } + } + } +} + +void AquaSalFrame::SetApplicationID( const OUString &/*rApplicationID*/ ) +{ +} + +void AquaSalFrame::ShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) +{ + doShowFullScreen(bFullScreen, nDisplay); +} + +void AquaSalFrame::doShowFullScreen( bool bFullScreen, sal_Int32 nDisplay ) +{ + if (!mpNSWindow) + { + if (Application::IsBitmapRendering() && bFullScreen) + SetPosSize(0, 0, 1024, 768, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); + return; + } + + SAL_INFO("vcl.osx", OSL_THIS_FUNC << ": mbFullScreen=" << mbFullScreen << ", bFullScreen=" << bFullScreen); + + if( mbFullScreen == bFullScreen ) + return; + + OSX_SALDATA_RUNINMAIN( ShowFullScreen( bFullScreen, nDisplay ) ) + + 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 = NSZeroRect; + // get correct screen + NSScreen* pScreen = nil; + NSArray* pScreens = [NSScreen screens]; + if( pScreens ) + { + if( nDisplay >= 0 && o3tl::make_unsigned(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 = [mpNSWindow screen]; + if( pScreen == nil ) + pScreen = [NSScreen mainScreen]; + + aNewContentRect = [pScreen frame]; + } + + if( bHideMenu ) + [NSMenu setMenuBarVisible:NO]; + + maFullScreenRect = [mpNSWindow frame]; + + [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aNewContentRect styleMask: mnStyleMask] display: mbShown ? YES : NO]; + } + else + { + [mpNSWindow setFrame: maFullScreenRect display: mbShown ? YES : NO]; + + // show the dock and the menubar + [NSMenu setMenuBarVisible:YES]; + } + + UpdateFrameGeometry(); + if (mbShown) + { + CallCallback(SalEvent::MoveResize, nullptr); + + // trigger filling our backbuffer + SendPaintEvent(); + } +} + +void AquaSalFrame::StartPresentation( bool bStart ) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( StartPresentation( bStart ) ) + + if( bStart ) + { + GetSalData()->maPresentationFrames.push_back( this ); + IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, + kIOPMAssertionLevelOn, + CFSTR("LibreOffice presentation running"), + &mnAssertionID); + [mpNSWindow setLevel: NSPopUpMenuWindowLevel]; + if( mbShown ) + [mpNSWindow makeMainWindow]; + } + else + { + GetSalData()->maPresentationFrames.remove( this ); + IOPMAssertionRelease(mnAssertionID); + [mpNSWindow setLevel: NSNormalWindowLevel]; + } +} + +void AquaSalFrame::SetAlwaysOnTop( bool ) +{ +} + +void AquaSalFrame::ToTop(SalFrameToTop nFlags) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( ToTop( nFlags ) ) + + if( ! (nFlags & SalFrameToTop::RestoreWhenMin) ) + { + if( ! [mpNSWindow isVisible] || [mpNSWindow isMiniaturized] ) + return; + } + if( nFlags & SalFrameToTop::GrabFocus ) + [mpNSWindow makeKeyAndOrderFront: NSApp]; + else + [mpNSWindow orderFront: NSApp]; +} + +NSCursor* AquaSalFrame::getCurrentCursor() +{ + OSX_SALDATA_RUNINMAIN_POINTER( getCurrentCursor(), NSCursor* ) + + NSCursor* pCursor = nil; + switch( mePointerStyle ) + { + case PointerStyle::Text: pCursor = [NSCursor IBeamCursor]; break; + case PointerStyle::Cross: pCursor = [NSCursor crosshairCursor]; break; + case PointerStyle::Hand: + case PointerStyle::Move: pCursor = [NSCursor openHandCursor]; break; + case PointerStyle::NSize: pCursor = [NSCursor resizeUpCursor]; break; + case PointerStyle::SSize: pCursor = [NSCursor resizeDownCursor]; break; + case PointerStyle::ESize: pCursor = [NSCursor resizeRightCursor]; break; + case PointerStyle::WSize: pCursor = [NSCursor resizeLeftCursor]; break; + case PointerStyle::Arrow: pCursor = [NSCursor arrowCursor]; break; + case PointerStyle::VSplit: + case PointerStyle::VSizeBar: + case PointerStyle::WindowNSize: + case PointerStyle::WindowSSize: + pCursor = [NSCursor resizeUpDownCursor]; break; + case PointerStyle::HSplit: + case PointerStyle::HSizeBar: + case PointerStyle::WindowESize: + case PointerStyle::WindowWSize: + pCursor = [NSCursor resizeLeftRightCursor]; break; + case PointerStyle::RefHand: pCursor = [NSCursor pointingHandCursor]; break; + + default: + pCursor = GetSalData()->getCursor( mePointerStyle ); + if( pCursor == nil ) + { + assert( false && "unmapped cursor" ); + pCursor = [NSCursor arrowCursor]; + } + break; + } + return pCursor; +} + +void AquaSalFrame::SetPointer( PointerStyle ePointerStyle ) +{ + if ( !mpNSWindow ) + return; + if( ePointerStyle == mePointerStyle ) + return; + + OSX_SALDATA_RUNINMAIN( SetPointer( ePointerStyle ) ) + + mePointerStyle = ePointerStyle; + + [mpNSWindow invalidateCursorRectsForView: mpNSView]; +} + +void AquaSalFrame::SetPointerPos( long nX, long nY ) +{ + OSX_SALDATA_RUNINMAIN( SetPointerPos( nX, nY ) ) + + // FIXME: use Cocoa functions + // FIXME: multiscreen support + CGPoint aPoint = { static_cast(nX + maGeometry.nX), static_cast(nY + maGeometry.nY) }; + CGDirectDisplayID mainDisplayID = CGMainDisplayID(); + CGDisplayMoveCursorToPoint( mainDisplayID, aPoint ); +} + +void AquaSalFrame::Flush() +{ + if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) + return; + + OSX_SALDATA_RUNINMAIN( Flush() ) + + [mpNSView 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 ) + { + [mpNSView display]; + } +} + +void AquaSalFrame::Flush( const tools::Rectangle& rRect ) +{ + if( !(mbGraphics && mpGraphics && mpNSView && mbShown) ) + return; + + OSX_SALDATA_RUNINMAIN( Flush( rRect ) ) + + NSRect aNSRect = { { static_cast(rRect.Left()), static_cast(rRect.Top()) }, { static_cast(rRect.GetWidth()), static_cast(rRect.GetHeight()) } }; + VCLToCocoa( aNSRect, false ); + [mpNSView 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 ) + { + [mpNSView display]; + } +} + +void AquaSalFrame::SetInputContext( SalInputContext* pContext ) +{ + if (!pContext) + { + mnICOptions = InputContextFlags::NONE; + return; + } + + mnICOptions = pContext->mnOptions; + + if(!(pContext->mnOptions & InputContextFlags::Text)) + return; +} + +void AquaSalFrame::EndExtTextInput( EndExtTextInputFlags ) +{ +} + +OUString AquaSalFrame::GetKeyName( sal_uInt16 nKeyCode ) +{ + static std::map< sal_uInt16, OUString > aKeyMap; + if( aKeyMap.empty() ) + { + sal_uInt16 i; + for( i = KEY_A; i <= KEY_Z; i++ ) + aKeyMap[ i ] = OUString( sal_Unicode( 'A' + (i - KEY_A) ) ); + for( i = KEY_0; i <= KEY_9; i++ ) + aKeyMap[ i ] = OUString( sal_Unicode( '0' + (i - KEY_0) ) ); + for( i = KEY_F1; i <= KEY_F26; i++ ) + { + aKeyMap[ i ] = "F" + OUString::number(i - KEY_F1 + 1); + } + + aKeyMap[ KEY_DOWN ] = OUString( u'\x21e3' ); + aKeyMap[ KEY_UP ] = OUString( u'\x21e1' ); + aKeyMap[ KEY_LEFT ] = OUString( u'\x21e0' ); + aKeyMap[ KEY_RIGHT ] = OUString( u'\x21e2' ); + aKeyMap[ KEY_HOME ] = OUString( u'\x2196' ); + aKeyMap[ KEY_END ] = OUString( u'\x2198' ); + aKeyMap[ KEY_PAGEUP ] = OUString( u'\x21de' ); + aKeyMap[ KEY_PAGEDOWN ] = OUString( u'\x21df' ); + aKeyMap[ KEY_RETURN ] = OUString( u'\x21a9' ); + aKeyMap[ KEY_ESCAPE ] = "esc"; + aKeyMap[ KEY_TAB ] = OUString( u'\x21e5' ); + aKeyMap[ KEY_BACKSPACE ]= OUString( u'\x232b' ); + aKeyMap[ KEY_SPACE ] = OUString( u'\x2423' ); + aKeyMap[ KEY_DELETE ] = OUString( u'\x2326' ); + aKeyMap[ KEY_ADD ] = "+"; + aKeyMap[ KEY_SUBTRACT ] = "-"; + aKeyMap[ KEY_DIVIDE ] = "/"; + aKeyMap[ KEY_MULTIPLY ] = "*"; + aKeyMap[ KEY_POINT ] = "."; + aKeyMap[ KEY_COMMA ] = ","; + aKeyMap[ KEY_LESS ] = "<"; + aKeyMap[ KEY_GREATER ] = ">"; + aKeyMap[ KEY_EQUAL ] = "="; + aKeyMap[ KEY_OPEN ] = OUString( u'\x23cf' ); + aKeyMap[ KEY_TILDE ] = "~"; + aKeyMap[ KEY_BRACKETLEFT ] = "["; + aKeyMap[ KEY_BRACKETRIGHT ] = "]"; + aKeyMap[ KEY_SEMICOLON ] = ";"; + aKeyMap[ KEY_QUOTERIGHT ] = "'"; + + /* yet unmapped KEYCODES: + aKeyMap[ KEY_INSERT ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_CUT ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_COPY ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_PASTE ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_UNDO ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_REPEAT ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_FIND ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_PROPERTIES ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_FRONT ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_CONTEXTMENU ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_MENU ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_HELP ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_HANGUL_HANJA ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_DECIMAL ] = OUString( sal_Unicode( ) ); + aKeyMap[ KEY_QUOTELEFT ]= OUString( sal_Unicode( ) ); + aKeyMap[ KEY_CAPSLOCK ]= OUString( sal_Unicode( ) ); + aKeyMap[ KEY_NUMLOCK ]= OUString( sal_Unicode( ) ); + aKeyMap[ KEY_SCROLLLOCK ]= OUString( sal_Unicode( ) ); + */ + + } + + OUStringBuffer aResult( 16 ); + + sal_uInt16 nUnmodifiedCode = (nKeyCode & KEY_CODE_MASK); + std::map< sal_uInt16, OUString >::const_iterator it = aKeyMap.find( nUnmodifiedCode ); + if( it != aKeyMap.end() ) + { + if( (nKeyCode & KEY_SHIFT) != 0 ) + aResult.append( u'\x21e7' ); // shift + if( (nKeyCode & KEY_MOD1) != 0 ) + aResult.append( u'\x2318' ); // command + if( (nKeyCode & KEY_MOD2) != 0 ) + aResult.append( u'\x2325' ); // alternate + if( (nKeyCode & KEY_MOD3) != 0 ) + aResult.append( u'\x2303' ); // control + + aResult.append( it->second ); + } + + return aResult.makeStringAndClear(); +} + +static void getAppleScrollBarVariant(StyleSettings &rSettings) +{ + bool bIsScrollbarDoubleMax = true; // default is DoubleMax + + CFStringRef AppleScrollBarType = CFSTR("AppleScrollBarVariant"); + if( AppleScrollBarType ) + { + CFStringRef ScrollBarVariant = static_cast(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 = static_cast(CFPreferencesCopyAppValue( jumpScroll, kCFPreferencesCurrentApplication )); + if( jumpStr ) + { + if( CFGetTypeID( jumpStr ) == CFBooleanGetTypeID() ) + rSettings.SetPrimaryButtonWarpsSlider(jumpStr == kCFBooleanTrue); + CFRelease( jumpStr ); + } + CFRelease( jumpScroll ); + } +} + +static Color getColor( NSColor* pSysColor, const Color& rDefault, NSWindow* pWin ) +{ + Color aRet( rDefault ); + if( pSysColor ) + { + // transform to RGB +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'colorUsingColorSpaceName:device:' is deprecated: first deprecated in macOS 10.14 - + // Use -colorUsingType: or -colorUsingColorSpace: instead" + NSColor* pRBGColor = [pSysColor colorUsingColorSpaceName: NSDeviceRGBColorSpace device: [pWin deviceDescription]]; +SAL_WNODEPRECATED_DECLARATIONS_POP + if( pRBGColor ) + { + CGFloat 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 vcl::Font getFont( NSFont* pFont, long nDPIY, const vcl::Font& rDefault ) +{ + vcl::Font aResult( rDefault ); + if( pFont ) + { + aResult.SetFamilyName( GetOUString( [pFont familyName] ) ); + aResult.SetFontHeight( static_cast(([pFont pointSize] * 72.0 / static_cast(nDPIY))+0.5) ); + aResult.SetItalic( ([pFont italicAngle] != 0.0) ? ITALIC_NORMAL : ITALIC_NONE ); + // FIMXE: bold ? + } + + return aResult; +} + +void AquaSalFrame::getResolution( sal_Int32& o_rDPIX, sal_Int32& o_rDPIY ) +{ + OSX_SALDATA_RUNINMAIN( getResolution( o_rDPIX, o_rDPIY ) ) + + if( ! mpGraphics ) + { + AcquireGraphics(); + 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 ) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( UpdateSettings( rSettings ) ) + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'lockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView + // and implement -drawRect:; AppKit's automatic deferred display mechanism will call + // -drawRect: as necessary to display the view." + if (![mpNSView lockFocusIfCanDraw]) + return; +SAL_WNODEPRECATED_DECLARATIONS_POP + + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + + // Background Color + Color aBackgroundColor( 0xEC, 0xEC, 0xEC ); + aStyleSettings.BatchSetBackgrounds( aBackgroundColor, false ); + aStyleSettings.SetLightBorderColor( aBackgroundColor ); + + Color aInactiveTabColor( aBackgroundColor ); + aInactiveTabColor.DecreaseLuminance( 32 ); + aStyleSettings.SetInactiveTabColor( aInactiveTabColor ); + + Color aShadowColor( aStyleSettings.GetShadowColor() ); + aShadowColor.IncreaseLuminance( 32 ); + aStyleSettings.SetShadowColor( aShadowColor ); + + // get the system font settings + vcl::Font aAppFont = aStyleSettings.GetAppFont(); + sal_Int32 nDPIX = 72, nDPIY = 72; + getResolution( nDPIX, nDPIY ); + aAppFont = getFont( [NSFont systemFontOfSize: 0], nDPIY, aAppFont ); + + aStyleSettings.SetToolbarIconSize( ToolbarIconSize::Large ); + + // TODO: better mapping of macOS<->LibreOffice font settings + vcl::Font aLabelFont( getFont( [NSFont labelFontOfSize: 0], nDPIY, aAppFont ) ); + aStyleSettings.BatchSetFonts( aAppFont, aLabelFont ); + vcl::Font aMenuFont( getFont( [NSFont menuFontOfSize: 0], nDPIY, aAppFont ) ); + aStyleSettings.SetMenuFont( aMenuFont ); + + vcl::Font aTitleFont( getFont( [NSFont titleBarFontOfSize: 0], nDPIY, aAppFont ) ); + aStyleSettings.SetTitleFont( aTitleFont ); + aStyleSettings.SetFloatTitleFont( aTitleFont ); + + vcl::Font aTooltipFont(getFont([NSFont toolTipsFontOfSize: 0], nDPIY, aAppFont)); + aStyleSettings.SetHelpFont(aTooltipFont); + + Color aHighlightColor( getColor( [NSColor selectedTextBackgroundColor], + aStyleSettings.GetHighlightColor(), mpNSWindow ) ); + aStyleSettings.SetHighlightColor( aHighlightColor ); + Color aHighlightTextColor( getColor( [NSColor selectedTextColor], + aStyleSettings.GetHighlightTextColor(), mpNSWindow ) ); + aStyleSettings.SetHighlightTextColor( aHighlightTextColor ); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + Color aMenuHighlightColor( getColor( [NSColor selectedMenuItemColor], + aStyleSettings.GetMenuHighlightColor(), mpNSWindow ) ); +#pragma clang diagnostic pop + aStyleSettings.SetMenuHighlightColor( aMenuHighlightColor ); + Color aMenuHighlightTextColor( getColor( [NSColor selectedMenuItemTextColor], + aStyleSettings.GetMenuHighlightTextColor(), mpNSWindow ) ); + aStyleSettings.SetMenuHighlightTextColor( aMenuHighlightTextColor ); + + aStyleSettings.SetMenuColor( aBackgroundColor ); + Color aMenuTextColor( getColor( [NSColor textColor], + aStyleSettings.GetMenuTextColor(), mpNSWindow ) ); + aStyleSettings.SetMenuTextColor( aMenuTextColor ); + aStyleSettings.SetMenuBarTextColor( aMenuTextColor ); + aStyleSettings.SetMenuBarRolloverTextColor( aMenuTextColor ); + aStyleSettings.SetMenuBarHighlightTextColor(aStyleSettings.GetMenuHighlightTextColor()); + + // Set text colors for buttons and their different status according to OS settings, typically white for selected buttons, + // black otherwise + + Color aControlTextColor(getColor([NSColor controlTextColor], COL_BLACK, mpNSWindow)); + Color aSelectedControlTextColor(getColor([NSColor alternateSelectedControlTextColor], COL_WHITE, mpNSWindow)); + aStyleSettings.SetDefaultButtonTextColor(aSelectedControlTextColor); + aStyleSettings.SetButtonTextColor(aControlTextColor); + aStyleSettings.SetDefaultActionButtonTextColor(aSelectedControlTextColor); + aStyleSettings.SetActionButtonTextColor(aControlTextColor); + aStyleSettings.SetFlatButtonTextColor(aControlTextColor); + aStyleSettings.SetDefaultButtonRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetButtonRolloverTextColor(aControlTextColor); + aStyleSettings.SetDefaultActionButtonRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetActionButtonRolloverTextColor(aControlTextColor); + aStyleSettings.SetFlatButtonRolloverTextColor(aControlTextColor); + aStyleSettings.SetDefaultButtonPressedRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetButtonPressedRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetDefaultActionButtonPressedRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetActionButtonPressedRolloverTextColor(aSelectedControlTextColor); + aStyleSettings.SetFlatButtonPressedRolloverTextColor(aControlTextColor); + + // Set text colors for tabs according to OS settings, typically white for selected buttons, black otherwise + + aStyleSettings.SetTabTextColor(aControlTextColor); + aStyleSettings.SetTabHighlightTextColor(aSelectedControlTextColor); + + aStyleSettings.SetCursorBlinkTime( mnBlinkCursorDelay ); + + // no mnemonics on macOS + aStyleSettings.SetOptions( aStyleSettings.GetOptions() | StyleSettingsOptions::NoMnemonics ); + + getAppleScrollBarVariant(aStyleSettings); + + // set scrollbar size +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSRegularControlSize' is deprecated: first deprecated in macOS 10.12 + aStyleSettings.SetScrollBarSize( static_cast([NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]) ); +SAL_WNODEPRECATED_DECLARATIONS_POP + // images in menus false for MacOSX + aStyleSettings.SetPreferredUseImagesInMenus( false ); + aStyleSettings.SetHideDisabledMenuItems( true ); + aStyleSettings.SetPreferredContextMenuShortcuts( false ); + + rSettings.SetStyleSettings( aStyleSettings ); + + // don't draw frame around each and every toolbar + ImplGetSVData()->maNWFData.mbDockingAreaAvoidTBFrames = true; + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'unlockFocus' is deprecated: first deprecated in macOS 10.14 - To draw, subclass NSView + // and implement -drawRect:; AppKit's automatic deferred display mechanism will call + // -drawRect: as necessary to display the view." + [mpNSView unlockFocus]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +const SystemEnvData* AquaSalFrame::GetSystemData() const +{ + return &maSysData; +} + +void AquaSalFrame::Beep() +{ + OSX_SALDATA_RUNINMAIN( Beep() ) + NSBeep(); +} + +void AquaSalFrame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags) +{ + if (!mpNSWindow && !Application::IsBitmapRendering()) + return; + + OSX_SALDATA_RUNINMAIN( SetPosSize( nX, nY, nWidth, nHeight, nFlags ) ) + + SalEvent nEvent = PreparePosSize(nX, nY, nWidth, nHeight, nFlags); + if (Application::IsBitmapRendering()) + return; + + if( [mpNSWindow isMiniaturized] ) + [mpNSWindow deminiaturize: NSApp]; // expand the window + + NSRect aFrameRect = [mpNSWindow frame]; + NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask]; + + // position is always relative to parent frame + NSRect aParentContentRect; + + if( mpParent ) + { + if( AllSettings::GetLayoutRTL() ) + { + if( (nFlags & SAL_FRAME_POSSIZE_WIDTH) != 0 ) + nX = mpParent->maGeometry.nWidth - nWidth-1 - nX; + else + nX = mpParent->maGeometry.nWidth - static_cast( aContentRect.size.width-1) - nX; + } + NSRect aParentFrameRect = [mpParent->mpNSWindow 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 + { + [mpNSWindow setFrame: [NSWindow frameRectForContentRect: aContentRect styleMask: mnStyleMask] display: NO]; + } + + UpdateFrameGeometry(); + + if (nEvent != SalEvent::NONE) + CallCallback(nEvent, nullptr); + + if( mbShown && bPaint ) + { + // trigger filling our backbuffer + SendPaintEvent(); + + // now inform the system that the views need to be drawn + [mpNSWindow display]; + } +} + +void AquaSalFrame::GetWorkArea( tools::Rectangle& rRect ) +{ + if (!mpNSWindow) + { + if (Application::IsBitmapRendering()) + rRect = tools::Rectangle(Point(0, 0), Size(1024, 768)); + return; + } + + OSX_SALDATA_RUNINMAIN( GetWorkArea( rRect ) ) + + NSScreen* pScreen = [mpNSWindow screen]; + if( pScreen == nil ) + pScreen = [NSScreen mainScreen]; + NSRect aRect = [pScreen visibleFrame]; + CocoaToVCL( aRect ); + rRect.SetLeft( static_cast(aRect.origin.x) ); + rRect.SetTop( static_cast(aRect.origin.y) ); + rRect.SetRight( static_cast(aRect.origin.x + aRect.size.width - 1) ); + rRect.SetBottom( static_cast(aRect.origin.y + aRect.size.height - 1) ); +} + +SalFrame::SalPointerState AquaSalFrame::GetPointerState() +{ + OSX_SALDATA_RUNINMAIN_UNION( GetPointerState(), state ) + + SalPointerState state; + state.mnState = 0; + + // get position + NSPoint aPt = [mpNSWindow mouseLocationOutsideOfEventStream]; + CocoaToVCL( aPt, false ); + state.maPos = Point(static_cast(aPt.x), static_cast(aPt.y)); + + NSEvent* pCur = [NSApp currentEvent]; + bool bMouseEvent = false; + if( pCur ) + { + bMouseEvent = true; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSLeftMouseDown' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftMouseDragged' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftMouseUp' is deprecated: first deprecated in macOS 10.12 + // 'NSMouseMoved' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseDown' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseDragged' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseUp' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseDown' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseDragged' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseUp' is deprecated: first deprecated in macOS 10.12 + 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; + } +SAL_WNODEPRECATED_DECLARATIONS_POP + } + if( bMouseEvent ) + { + unsigned int nMask = static_cast([pCur modifierFlags]); +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + 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; +SAL_WNODEPRECATED_DECLARATIONS_POP + + } + 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_NSApplication::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; +} + +KeyIndicatorState AquaSalFrame::GetIndicatorState() +{ + return KeyIndicatorState::NONE; +} + +void AquaSalFrame::SimulateKeyPress( sal_uInt16 /*nKeyCode*/ ) +{ +} + +bool AquaSalFrame::SetPluginParent( SystemParentData* ) +{ + // plugin parent may be killed unexpectedly by + // plugging process; + + //TODO: implement + return false; +} + +bool AquaSalFrame::MapUnicodeToKeyCode( sal_Unicode , LanguageType , vcl::KeyCode& ) +{ + // not supported yet + return false; +} + +LanguageType AquaSalFrame::GetInputLanguage() +{ + //TODO: implement + return LANGUAGE_DONTKNOW; +} + +void AquaSalFrame::DrawMenuBar() +{ +} + +void AquaSalFrame::SetMenu( SalMenu* pSalMenu ) +{ + OSX_SALDATA_RUNINMAIN( SetMenu( pSalMenu ) ) + + AquaSalMenu* pMenu = static_cast(pSalMenu); + SAL_WARN_IF( pMenu && !pMenu->mbMenuBar, "vcl", "setting non menubar on frame" ); + mpMenu = pMenu; + if( mpMenu ) + mpMenu->setMainMenu(); +} + +void AquaSalFrame::SetExtendedFrameStyle( SalExtStyle nStyle ) +{ + if ( !mpNSWindow ) + { + mnExtStyle = nStyle; + return; + } + + OSX_SALDATA_RUNINMAIN( SetExtendedFrameStyle( nStyle ) ) + + if( (mnExtStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) != (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ) + [mpNSWindow setDocumentEdited: (nStyle & SAL_FRAME_EXT_STYLE_DOCMODIFIED) ? YES : NO]; + + mnExtStyle = nStyle; +} + +SalFrame* AquaSalFrame::GetParent() const +{ + return mpParent; +} + +void AquaSalFrame::SetParent( SalFrame* pNewParent ) +{ + bool bShown = mbShown; + // remove from child list + if (bShown) + Show(false); + mpParent = static_cast(pNewParent); + // insert to correct parent and paint + Show( bShown ); +} + +void AquaSalFrame::UpdateFrameGeometry() +{ + bool bFirstTime = (mnTrackingRectTag == 0); + mbGeometryDidChange = false; + + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( UpdateFrameGeometry() ) + + // keep in mind that view and window coordinates are lower left + // whereas vcl's are upper left + + // update screen rect + NSScreen * pScreen = [mpNSWindow screen]; + if( pScreen ) + { + NSRect aNewScreenRect = [pScreen frame]; + if (bFirstTime || !NSEqualRects(maScreenRect, aNewScreenRect)) + { + mbGeometryDidChange = true; + maScreenRect = aNewScreenRect; + } + NSArray* pScreens = [NSScreen screens]; + if( pScreens ) + { + unsigned int nNewDisplayScreenNumber = [pScreens indexOfObject: pScreen]; + if (bFirstTime || maGeometry.nDisplayScreenNumber != nNewDisplayScreenNumber) + { + mbGeometryDidChange = true; + maGeometry.nDisplayScreenNumber = nNewDisplayScreenNumber; + } + } + } + + NSRect aFrameRect = [mpNSWindow frame]; + NSRect aContentRect = [NSWindow contentRectForFrameRect: aFrameRect styleMask: mnStyleMask]; + + NSRect aTrackRect = { NSZeroPoint, aContentRect.size }; + + if (bFirstTime || !NSEqualRects(maTrackingRect, aTrackRect)) + { + mbGeometryDidChange = true; + maTrackingRect = aTrackRect; + + // release old track rect + [mpNSView removeTrackingRect: mnTrackingRectTag]; + // install the new track rect + mnTrackingRectTag = [mpNSView addTrackingRect: aTrackRect owner: mpNSView userData: nil assumeInside: NO]; + } + + // convert to vcl convention + CocoaToVCL( aFrameRect ); + CocoaToVCL( aContentRect ); + + if (bFirstTime || !NSEqualRects(maContentRect, aContentRect) || !NSEqualRects(maFrameRect, aFrameRect)) + { + mbGeometryDidChange = true; + + maContentRect = aContentRect; + maFrameRect = aFrameRect; + + maGeometry.nX = static_cast(aContentRect.origin.x); + maGeometry.nY = static_cast(aContentRect.origin.y); + + maGeometry.nLeftDecoration = static_cast(aContentRect.origin.x - aFrameRect.origin.x); + maGeometry.nRightDecoration = static_cast((aFrameRect.origin.x + aFrameRect.size.width) - + (aContentRect.origin.x + aContentRect.size.width)); + + maGeometry.nTopDecoration = static_cast(aContentRect.origin.y - aFrameRect.origin.y); + maGeometry.nBottomDecoration = static_cast((aFrameRect.origin.y + aFrameRect.size.height) - + (aContentRect.origin.y + aContentRect.size.height)); + + maGeometry.nWidth = static_cast(aContentRect.size.width); + maGeometry.nHeight = static_cast(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 = nullptr; +} + +void AquaSalFrame::ResetClipRegion() +{ + doResetClipRegion(); +} + +void AquaSalFrame::doResetClipRegion() +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( ResetClipRegion() ) + + // release old path and indicate no clipping + CGPathRelease( mrClippingPath ); + mrClippingPath = nullptr; + + if( mpNSView && mbShown ) + [mpNSView setNeedsDisplay: YES]; + [mpNSWindow setOpaque: YES]; + [mpNSWindow invalidateShadow]; +} + +void AquaSalFrame::BeginSetClipRegion( sal_uInt32 nRects ) +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( BeginSetClipRegion( nRects ) ) + + // release old path + if( mrClippingPath ) + { + CGPathRelease( mrClippingPath ); + mrClippingPath = nullptr; + } + + if( maClippingRects.size() > SAL_CLIPRECT_COUNT && nRects < maClippingRects.size() ) + { + std::vector aEmptyVec; + maClippingRects.swap( aEmptyVec ); + } + maClippingRects.clear(); + maClippingRects.reserve( nRects ); +} + +void AquaSalFrame::UnionClipRegion( long nX, long nY, long nWidth, long nHeight ) +{ + // #i113170# may not be the main thread if called from UNO API + SalData::ensureThreadAutoreleasePool(); + + if( nWidth && nHeight ) + { + NSRect aRect = { { static_cast(nX), static_cast(nY) }, { static_cast(nWidth), static_cast(nHeight) } }; + VCLToCocoa( aRect, false ); + maClippingRects.push_back( CGRectMake(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height) ); + } +} + +void AquaSalFrame::EndSetClipRegion() +{ + if ( !mpNSWindow ) + return; + + OSX_SALDATA_RUNINMAIN( EndSetClipRegion() ) + + if( ! maClippingRects.empty() ) + { + mrClippingPath = CGPathCreateMutable(); + CGPathAddRects( mrClippingPath, nullptr, maClippingRects.data(), maClippingRects.size() ); + } + if( mpNSView && mbShown ) + [mpNSView setNeedsDisplay: YES]; + [mpNSWindow setOpaque: (mrClippingPath != nullptr) ? NO : YES]; + [mpNSWindow setBackgroundColor: [NSColor clearColor]]; + // shadow is invalidated when view gets drawn again +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salframeview.mm b/vcl/osx/salframeview.mm new file mode 100644 index 000000000..d26617eb3 --- /dev/null +++ b/vcl/osx/salframeview.mm @@ -0,0 +1,1788 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define WHEEL_EVENT_FACTOR 1.5 + +static sal_uInt16 ImplGetModifierMask( unsigned int nMask ) +{ + sal_uInt16 nRet = 0; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + 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; +SAL_WNODEPRECATED_DECLARATIONS_POP + return nRet; +} + +static sal_uInt16 ImplMapCharCode( sal_Unicode aCode ) +{ + static sal_uInt16 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 sal_uInt16 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 + }; + + sal_uInt16 nKeyCode = 0; + if( aCode < SAL_N_ELEMENTS( aKeyCodeMap) ) + nKeyCode = aKeyCodeMap[ aCode ]; + else if( aCode >= 0xf700 && aCode < 0xf780 ) + nKeyCode = aFunctionKeyCodeMap[ aCode - 0xf700 ]; + return nKeyCode; +} + +static sal_uInt16 ImplMapKeyCode(sal_uInt16 nKeyCode) +{ + /* + http://stackoverflow.com/questions/2080312/where-can-i-find-a-list-of-key-codes-for-use-with-cocoas-nsevent-class/2080324#2080324 + /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h + */ + + static sal_uInt16 aKeyCodeMap[ 0x80 ] = + { + KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X, + KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R, + KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5, + KEY_EQUAL, KEY_9, KEY_7, KEY_SUBTRACT, KEY_8, KEY_0, KEY_BRACKETRIGHT, KEY_0, + KEY_U, KEY_BRACKETLEFT, KEY_I, KEY_P, KEY_RETURN, KEY_L, KEY_J, KEY_QUOTERIGHT, + KEY_K, KEY_SEMICOLON, 0, KEY_COMMA, KEY_DIVIDE, KEY_N, KEY_M, KEY_POINT, + KEY_TAB, KEY_SPACE, KEY_QUOTELEFT, KEY_DELETE, 0, KEY_ESCAPE, 0, 0, + 0, KEY_CAPSLOCK, 0, 0, 0, 0, 0, 0, + KEY_F17, KEY_DECIMAL, 0, KEY_MULTIPLY, 0, KEY_ADD, 0, 0, + 0, 0, 0, KEY_DIVIDE, KEY_RETURN, 0, KEY_SUBTRACT, KEY_F18, + KEY_F19, KEY_EQUAL, 0, 0, 0, 0, 0, 0, + 0, 0, KEY_F20, 0, 0, 0, 0, 0, + KEY_F5, KEY_F6, KEY_F7, KEY_F3, KEY_F8, KEY_F9, 0, KEY_F11, + 0, KEY_F13, KEY_F16, KEY_F14, 0, KEY_F10, 0, KEY_F12, + 0, KEY_F15, KEY_HELP, KEY_HOME, KEY_PAGEUP, KEY_DELETE, KEY_F4, KEY_END, + KEY_F2, KEY_PAGEDOWN, KEY_F1, KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0 + }; + + if (nKeyCode < SAL_N_ELEMENTS(aKeyCodeMap)) + return aKeyCodeMap[nKeyCode]; + return 0; +} + +// store the frame the mouse last entered +static AquaSalFrame* s_pMouseFrame = nullptr; +// store the last pressed button for enter/exit events +// which lack that information +static sal_uInt16 s_nLastButton = 0; + +static AquaSalFrame* getMouseContainerFrame() +{ + AquaSalFrame* pDispatchFrame = nullptr; + NSArray* aWindows = [NSWindow windowNumbersWithOptions:0]; + for(NSUInteger i = 0; i < [aWindows count] && ! pDispatchFrame; i++ ) + { + NSWindow* pWin = [NSApp windowWithWindowNumber:[[aWindows objectAtIndex:i] integerValue]]; + if( pWin && [pWin isMemberOfClass: [SalFrameWindow class]] && [static_cast(pWin) containsMouse] ) + pDispatchFrame = [static_cast(pWin) getSalFrame]; + } + return pDispatchFrame; +} + +@implementation SalFrameWindow +-(id)initWithSalFrame: (AquaSalFrame*)pFrame +{ + mDraggingDestinationHandler = nil; + mpFrame = pFrame; + NSRect aRect = { { static_cast(pFrame->maGeometry.nX), static_cast(pFrame->maGeometry.nY) }, + { static_cast(pFrame->maGeometry.nWidth), static_cast(pFrame->maGeometry.nHeight) } }; + pFrame->VCLToCocoa( aRect ); + NSWindow* pNSWindow = [super initWithContentRect: aRect + styleMask: mpFrame->getStyleMask() + backing: NSBackingStoreBuffered + defer: Application::IsHeadlessModeEnabled()]; + + // Disallow full-screen mode on macOS >= 10.11 where it is enabled by default. We don't want it + // for now as it will just be confused with LibreOffice's home-grown full-screen concept, with + // which it has nothing to do, and one can get into all kinds of weird states by using them + // intermixedly. + + // Ideally we should use the system full-screen mode and adapt the code for the home-grown thing + // to be in sync with that instead. (And we would then not need the button to get out of + // full-screen mode, as the normal way to get out of it is to either click on the green bubble + // again, or invoke the keyboard command again.) + + // (Confusingly, at the moment the home-grown full-screen mode is bound to Cmd+Shift+F, which is + // the keyboard command normally used in apps to get in and out of the system full-screen mode.) + + // Disabling system full-screen mode makes the green button on the title bar (on macOS >= 10.11) + // show a plus sign instead, and clicking it becomes identical to double-clicking the title bar, + // i.e. it maximizes / unmaximises the window. Sure, that state can also be confused with LO's + // home-grown full-screen mode. Oh well. + + [pNSWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenNone]; + + // Disable window restoration until we support it directly + [pNSWindow setRestorable: NO]; + + return static_cast(pNSWindow); +} + +-(AquaSalFrame*)getSalFrame +{ + return mpFrame; +} + +-(void)displayIfNeeded +{ + if( GetSalData() && GetSalData()->mpInstance ) + { + SolarMutexGuard aGuard; + [super displayIfNeeded]; + } +} + +-(BOOL)containsMouse +{ + // is this event actually inside that NSWindow ? + NSPoint aPt = [NSEvent mouseLocation]; + NSRect aFrameRect = [self frame]; + bool bInRect = NSPointInRect( aPt, aFrameRect ); + return bInRect; +} + +-(BOOL)canBecomeKeyWindow +{ + if( (mpFrame->mnStyle & + ( SalFrameStyleFlags::FLOAT | + SalFrameStyleFlags::TOOLTIP | + SalFrameStyleFlags::INTRO + )) == SalFrameStyleFlags::NONE ) + return YES; + if( mpFrame->mnStyle & SalFrameStyleFlags::OWNERDRAWDECORATION ) + return YES; + if( mpFrame->mbFullScreen ) + return YES; + return [super canBecomeKeyWindow]; +} + +-(void)windowDidBecomeKey: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + static const SalFrameStyleFlags nGuessDocument = SalFrameStyleFlags::MOVEABLE| + SalFrameStyleFlags::SIZEABLE| + SalFrameStyleFlags::CLOSEABLE; + + if( mpFrame->mpMenu ) + mpFrame->mpMenu->setMainMenu(); + else if( ! mpFrame->mpParent && + ( (mpFrame->mnStyle & nGuessDocument) == nGuessDocument || // set default menu for e.g. help + mpFrame->mbFullScreen ) ) // set 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, nullptr ); + mpFrame->SendPaintEvent(); // repaint controls as active + } +} + +-(void)windowDidResignKey: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->CallCallback(SalEvent::LoseFocus, nullptr); + mpFrame->SendPaintEvent(); // repaint controls as inactive + } +} + +-(void)windowDidChangeScreen: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->screenParametersChanged(); +} + +-(void)windowDidMove: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->UpdateFrameGeometry(); + mpFrame->CallCallback( SalEvent::Move, nullptr ); + } +} + +-(void)windowDidResize: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->UpdateFrameGeometry(); + mpFrame->CallCallback( SalEvent::Resize, nullptr ); + mpFrame->SendPaintEvent(); + } +} + +-(void)windowDidMiniaturize: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->mbShown = false; + mpFrame->UpdateFrameGeometry(); + mpFrame->CallCallback( SalEvent::Resize, nullptr ); + } +} + +-(void)windowDidDeminiaturize: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->mbShown = true; + mpFrame->UpdateFrameGeometry(); + mpFrame->CallCallback( SalEvent::Resize, nullptr ); + } +} + +-(BOOL)windowShouldClose: (NSNotification*)pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + bool bRet = true; + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + // #i84461# end possible input + mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); + if( AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->CallCallback( SalEvent::Close, nullptr ); + bRet = false; // application will close the window or not, AppKit shouldn't + AquaSalTimer *pTimer = static_cast( ImplGetSVData()->maSchedCtx.mpSalTimer ); + assert( pTimer ); + pTimer->handleWindowShouldClose(); + } + } + + return bRet; +} + +-(void)windowDidEnterFullScreen: (NSNotification*)pNotification +{ + SolarMutexGuard aGuard; + + if( !mpFrame || !AquaSalFrame::isAlive( mpFrame)) + return; + mpFrame->mbFullScreen = true; + (void)pNotification; +} + +-(void)windowDidExitFullScreen: (NSNotification*)pNotification +{ + SolarMutexGuard aGuard; + + if( !mpFrame || !AquaSalFrame::isAlive( mpFrame)) + return; + mpFrame->mbFullScreen = false; + (void)pNotification; +} + +-(void)dockMenuItemTriggered: (id)sender +{ + (void)sender; + SolarMutexGuard aGuard; + + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->ToTop( SalFrameToTop::RestoreWhenMin | SalFrameToTop::GrabFocus ); +} + +-(css::uno::Reference < css::accessibility::XAccessibleContext >)accessibleContext +{ + return mpFrame -> GetWindow() -> GetAccessible() -> getAccessibleContext(); +} + +-(NSDragOperation)draggingEntered:(id )sender +{ + return [mDraggingDestinationHandler draggingEntered: sender]; +} + +-(NSDragOperation)draggingUpdated:(id )sender +{ + return [mDraggingDestinationHandler draggingUpdated: sender]; +} + +-(void)draggingExited:(id )sender +{ + [mDraggingDestinationHandler draggingExited: sender]; +} + +-(BOOL)prepareForDragOperation:(id )sender +{ + return [mDraggingDestinationHandler prepareForDragOperation: sender]; +} + +-(BOOL)performDragOperation:(id )sender +{ + return [mDraggingDestinationHandler performDragOperation: sender]; +} + +-(void)concludeDragOperation:(id )sender +{ + [mDraggingDestinationHandler concludeDragOperation: sender]; +} + +-(void)registerDraggingDestinationHandler:(id)theHandler +{ + mDraggingDestinationHandler = theHandler; +} + +-(void)unregisterDraggingDestinationHandler:(id)theHandler +{ + (void)theHandler; + mDraggingDestinationHandler = nil; +} + +@end + +@implementation SalFrameView ++(void)unsetMouseFrame: (AquaSalFrame*)pFrame +{ + if( pFrame == s_pMouseFrame ) + s_pMouseFrame = nullptr; +} + +-(id)initWithSalFrame: (AquaSalFrame*)pFrame +{ + if ((self = [super initWithFrame: [NSWindow contentRectForFrameRect: [pFrame->getNSWindow() frame] styleMask: pFrame->mnStyleMask]]) != nil) + { + mDraggingDestinationHandler = nil; + mpFrame = pFrame; + mMarkedRange = NSMakeRange(NSNotFound, 0); + mSelectedRange = NSMakeRange(NSNotFound, 0); + mpReferenceWrapper = nil; + mpMouseEventListener = nil; + mpLastSuperEvent = nil; + } + + mfLastMagnifyTime = 0.0; + return self; +} + +-(AquaSalFrame*)getSalFrame +{ + return mpFrame; +} + +-(void)resetCursorRects +{ + if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) + { + // FIXME: does this leak the returned NSCursor of getCurrentCursor ? + const NSRect aRect = { NSZeroPoint, NSMakeSize( mpFrame->maGeometry.nWidth, mpFrame->maGeometry.nHeight) }; + [self addCursorRect: aRect cursor: mpFrame->getCurrentCursor()]; + } +} + +-(BOOL)acceptsFirstResponder +{ + return YES; +} + +-(BOOL)acceptsFirstMouse: (NSEvent*)pEvent +{ + (void)pEvent; + return YES; +} + +-(BOOL)isOpaque +{ + if( !mpFrame) + return YES; + if( !AquaSalFrame::isAlive( mpFrame)) + return YES; + if( !mpFrame->getClipPath()) + return YES; + return NO; +} + +-(void)drawRect: (NSRect)aRect +{ + AquaSalInstance *pInstance = GetSalData()->mpInstance; + assert(pInstance); + if (!pInstance) + return; + + SolarMutexGuard aGuard; + if (!mpFrame || !AquaSalFrame::isAlive(mpFrame)) + return; + + const bool bIsLiveResize = [self inLiveResize]; + const bool bWasLiveResize = pInstance->mbIsLiveResize; + if (bWasLiveResize != bIsLiveResize) + { + pInstance->mbIsLiveResize = bIsLiveResize; + Scheduler::ProcessTaskScheduling(); + } + + AquaSalGraphics* pGraphics = mpFrame->mpGraphics; + if (pGraphics) + { + pGraphics->UpdateWindow(aRect); + if (mpFrame->getClipPath()) + [mpFrame->getNSWindow() invalidateShadow]; + } +} + +-(void)sendMouseEventToFrame: (NSEvent*)pEvent button:(sal_uInt16)nButton eventtype:(SalEvent)nEvent +{ + SolarMutexGuard aGuard; + + 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->getNSWindow() 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( [pEvent timestamp] * 1000.0 ); + pDispatchFrame->mnLastModifierFlags = [pEvent modifierFlags]; + + NSPoint aPt = [NSEvent mouseLocation]; + pDispatchFrame->CocoaToVCL( aPt ); + + sal_uInt16 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(aPt.x) - pDispatchFrame->maGeometry.nX; + aEvent.mnY = static_cast(aPt.y) - pDispatchFrame->maGeometry.nY; + aEvent.mnButton = nButton; + aEvent.mnCode = aEvent.mnButton | nModMask; + + if( AllSettings::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: nullptr]]; + } + + 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: nullptr]]; + } + 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; + + // #i107215# the only mouse events we get when inactive are enter/exit + // actually we would like to have all of them, but better none than some + if( [NSApp isActive] ) + [self sendMouseEventToFrame:pEvent button:s_nLastButton eventtype:SalEvent::MouseMove]; +} + +-(void)mouseExited: (NSEvent*)pEvent +{ + if( s_pMouseFrame == mpFrame ) + s_pMouseFrame = nullptr; + + // #i107215# the only mouse events we get when inactive are enter/exit + // actually we would like to have all of them, but better none than some + if( [NSApp isActive] ) + [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 +{ + SolarMutexGuard aGuard; + + // TODO: ?? -(float)magnification; + if( AquaSalFrame::isAlive( mpFrame ) ) + { + const NSTimeInterval fMagnifyTime = [pEvent timestamp]; + mpFrame->mnLastEventTime = static_cast( fMagnifyTime * 1000.0 ); + mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; + + // check if this is a new series of magnify events + static const NSTimeInterval fMaxDiffTime = 0.3; + const bool bNewSeries = (fMagnifyTime - mfLastMagnifyTime > fMaxDiffTime); + + if( bNewSeries ) + mfMagnifyDeltaSum = 0.0; + mfMagnifyDeltaSum += [pEvent magnification]; + + mfLastMagnifyTime = [pEvent timestamp]; +// TODO: change to 0.1 when CommandWheelMode::ZOOM handlers allow finer zooming control + static const float fMagnifyFactor = 0.25*500; // steps are 500 times smaller for -magnification + static const float fMinMagnifyStep = 15.0 / fMagnifyFactor; + if( fabs(mfMagnifyDeltaSum) <= fMinMagnifyStep ) + return; + + // adapt NSEvent-sensitivity to application expectations + // TODO: rather make CommandWheelMode::ZOOM handlers smarter + const float fDeltaZ = mfMagnifyDeltaSum * fMagnifyFactor; + int nDeltaZ = FRound( fDeltaZ ); + if( !nDeltaZ ) + { + // handle new series immediately + if( !bNewSeries ) + return; + nDeltaZ = (fDeltaZ >= 0.0) ? +1 : -1; + } + // eventually give credit for delta sum + mfMagnifyDeltaSum -= nDeltaZ / fMagnifyFactor; + + NSPoint aPt = [NSEvent mouseLocation]; + mpFrame->CocoaToVCL( aPt ); + + SalWheelMouseEvent aEvent; + aEvent.mnTime = mpFrame->mnLastEventTime; + aEvent.mnX = static_cast(aPt.x) - mpFrame->maGeometry.nX; + aEvent.mnY = static_cast(aPt.y) - mpFrame->maGeometry.nY; + aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); + aEvent.mnCode |= KEY_MOD1; // we want zooming, no scrolling + aEvent.mbDeltaIsPixel = true; + + if( AllSettings::GetLayoutRTL() ) + aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; + + aEvent.mnDelta = nDeltaZ; + aEvent.mnNotchDelta = (nDeltaZ >= 0) ? +1 : -1; + if( aEvent.mnDelta == 0 ) + aEvent.mnDelta = aEvent.mnNotchDelta; + aEvent.mbHorz = false; + sal_uInt32 nScrollLines = nDeltaZ; + if (nScrollLines == 0) + nScrollLines = 1; + aEvent.mnScrollLines = nScrollLines; + mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); + } +} + +- (void)rotateWithEvent: (NSEvent*)pEvent +{ + //Rotation : -(float)rotation; + // TODO: create new CommandType so rotation is available to the applications + (void)pEvent; +} + +- (void)swipeWithEvent: (NSEvent*)pEvent +{ + SolarMutexGuard aGuard; + + if( AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->mnLastEventTime = static_cast( [pEvent timestamp] * 1000.0 ); + mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; + + // merge pending scroll wheel events + CGFloat dX = 0.0; + CGFloat dY = 0.0; + for(;;) + { + dX += [pEvent deltaX]; + dY += [pEvent deltaY]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12 + NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask +SAL_WNODEPRECATED_DECLARATIONS_POP + 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(aPt.x) - mpFrame->maGeometry.nX; + aEvent.mnY = static_cast(aPt.y) - mpFrame->maGeometry.nY; + aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); + aEvent.mbDeltaIsPixel = true; + + if( AllSettings::GetLayoutRTL() ) + aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; + + if( dX != 0.0 ) + { + aEvent.mnDelta = static_cast(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(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 +{ + SolarMutexGuard aGuard; + + if( AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->mnLastEventTime = static_cast( [pEvent timestamp] * 1000.0 ); + mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; + + // merge pending scroll wheel events + CGFloat dX = 0.0; + CGFloat dY = 0.0; + for(;;) + { + dX += [pEvent deltaX]; + dY += [pEvent deltaY]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12 + NSEvent* pNextEvent = [NSApp nextEventMatchingMask: NSScrollWheelMask +SAL_WNODEPRECATED_DECLARATIONS_POP + 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(aPt.x) - mpFrame->maGeometry.nX; + aEvent.mnY = static_cast(aPt.y) - mpFrame->maGeometry.nY; + aEvent.mnCode = ImplGetModifierMask( mpFrame->mnLastModifierFlags ); + aEvent.mbDeltaIsPixel = false; + + if( AllSettings::GetLayoutRTL() ) + aEvent.mnX = mpFrame->maGeometry.nWidth-1-aEvent.mnX; + + if( dX != 0.0 ) + { + aEvent.mnDelta = static_cast(floor(dX)); + aEvent.mnNotchDelta = (dX < 0) ? -1 : +1; + if( aEvent.mnDelta == 0 ) + aEvent.mnDelta = aEvent.mnNotchDelta; + aEvent.mbHorz = true; + sal_uInt32 nScrollLines = fabs(dX) / WHEEL_EVENT_FACTOR; + if (nScrollLines == 0) + nScrollLines = 1; + aEvent.mnScrollLines = nScrollLines; + + mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); + } + if( dY != 0.0 && AquaSalFrame::isAlive( mpFrame ) ) + { + aEvent.mnDelta = static_cast(floor(dY)); + aEvent.mnNotchDelta = (dY < 0) ? -1 : +1; + if( aEvent.mnDelta == 0 ) + aEvent.mnDelta = aEvent.mnNotchDelta; + aEvent.mbHorz = false; + sal_uInt32 nScrollLines = fabs(dY) / WHEEL_EVENT_FACTOR; + if (nScrollLines == 0) + nScrollLines = 1; + aEvent.mnScrollLines = nScrollLines; + + mpFrame->CallCallback( SalEvent::WheelMouse, &aEvent ); + } + } +} + + +-(void)keyDown: (NSEvent*)pEvent +{ + SolarMutexGuard aGuard; + + if( AquaSalFrame::isAlive( mpFrame ) ) + { + mpLastEvent = pEvent; + mbInKeyInput = true; + mbNeedSpecialKeyHandle = false; + mbKeyHandled = false; + + mpFrame->mnLastEventTime = static_cast( [pEvent timestamp] * 1000.0 ); + mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; + + if( ! [self handleKeyDownException: pEvent] ) + { + NSArray* pArray = [NSArray arrayWithObject: pEvent]; + [self interpretKeyEvents: pArray]; + } + + mbInKeyInput = false; + } +} + +-(BOOL)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 + */ +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + if( (mpFrame->mnLastModifierFlags & (NSAlternateKeyMask | NSCommandKeyMask)) + == (NSAlternateKeyMask | NSCommandKeyMask) ) +SAL_WNODEPRECATED_DECLARATIONS_POP + { + if( [self sendSingleCharacter: mpLastEvent] ) + return YES; + } + } + return NO; +} + +-(void)flagsChanged: (NSEvent*)pEvent +{ + SolarMutexGuard aGuard; + + if( AquaSalFrame::isAlive( mpFrame ) ) + { + mpFrame->mnLastEventTime = static_cast( [pEvent timestamp] * 1000.0 ); + mpFrame->mnLastModifierFlags = [pEvent modifierFlags]; + } +} + +-(void)insertText:(id)aString replacementRange:(NSRange)replacementRange +{ + (void) replacementRange; // FIXME: surely it must be used + + SolarMutexGuard aGuard; + + 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 ] + ) + { + sal_uInt16 nKeyCode = ImplMapCharCode( aCharCode ); + unsigned int nLastModifiers = mpFrame->mnLastModifierFlags; + + // #i99567# + // find out the unmodified key code + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyUp' is deprecated: first deprecated in macOS 10.12 + // 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; + } +SAL_WNODEPRECATED_DECLARATIONS_POP + [self sendKeyInputAndReleaseToFrame: nKeyCode character: aCharCode modifiers: nLastModifiers]; + } + else + { + SalExtTextInputEvent aEvent; + aEvent.maText = aInsertString; + aEvent.mpTextAttr = nullptr; + aEvent.mnCursorPos = aInsertString.getLength(); + aEvent.mnCursorFlags = 0; + mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent ); + if( AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); + } + } + else + { + SalExtTextInputEvent aEvent; + aEvent.maText.clear(); + aEvent.mpTextAttr = nullptr; + aEvent.mnCursorPos = 0; + aEvent.mnCursorFlags = 0; + mpFrame->CallCallback( SalEvent::ExtTextInput, &aEvent ); + if( AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); + + } + mbKeyHandled = true; + [self unmarkText]; + } +} + +-(void)insertTab: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_TAB character: '\t' modifiers: 0]; +} + +-(void)insertBacktab: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: (KEY_TAB | KEY_SHIFT) character: '\t' modifiers: 0]; +} + +-(void)moveLeft: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: 0]; +} + +-(void)moveLeftAndModifySelection: (id)aSender +{ + (void)aSender; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + [self sendKeyInputAndReleaseToFrame: KEY_LEFT character: 0 modifiers: NSShiftKeyMask]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +-(void)moveBackwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_BACKWARD character: 0 modifiers: 0]; +} + +-(void)moveRight: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: 0]; +} + +-(void)moveRightAndModifySelection: (id)aSender +{ + (void)aSender; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + [self sendKeyInputAndReleaseToFrame: KEY_RIGHT character: 0 modifiers: NSShiftKeyMask]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +-(void)moveForwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_FORWARD character: 0 modifiers: 0]; +} + +-(void)moveWordLeft: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0]; +} + +-(void)moveWordBackward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_BACKWARD character: 0 modifiers: 0]; +} + +-(void)moveWordBackwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0]; +} + +-(void)moveWordLeftAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_BACKWARD character: 0 modifiers: 0]; +} + +-(void)moveWordRight: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0]; +} + +-(void)moveWordForward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_WORD_FORWARD character: 0 modifiers: 0]; +} + +-(void)moveWordForwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0]; +} + +-(void)moveWordRightAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD_FORWARD character: 0 modifiers: 0]; +} + +-(void)moveToEndOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToRightEndOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToEndOfLineAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToRightEndOfLineAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToLeftEndOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfLineAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToLeftEndOfLineAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; +} + +-(void)moveToEndOfParagraph: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveToEndOfParagraphAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveParagraphForward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveParagraphForwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfParagraph: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveParagraphBackward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfParagraphAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveParagraphBackwardAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)moveToEndOfDocument: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)scrollToEndOfDocument: (id)aSender +{ + (void)aSender; + // this is not exactly what we should do, but it makes "End" and "Shift-End" behave consistent + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)moveToEndOfDocumentAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_END_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfDocument: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)scrollToBeginningOfDocument: (id)aSender +{ + (void)aSender; + // this is not exactly what we should do, but it makes "Home" and "Shift-Home" behave consistent + [self sendKeyInputAndReleaseToFrame: css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)moveToBeginningOfDocumentAndModifySelection: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT character: 0 modifiers: 0]; +} + +-(void)moveUp: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_UP character: 0 modifiers: 0]; +} + +-(void)moveDown: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_DOWN character: 0 modifiers: 0]; +} + +-(void)insertNewline: (id)aSender +{ + (void)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 +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0]; +} + +-(void)deleteForward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_DELETE character: 0x7f modifiers: 0]; +} + +-(void)deleteBackwardByDecomposingPreviousCharacter: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_BACKSPACE character: '\b' modifiers: 0]; +} + +-(void)deleteWordBackward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_BACKWARD character: 0 modifiers: 0]; +} + +-(void)deleteWordForward: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_WORD_FORWARD character: 0 modifiers: 0]; +} + +-(void)deleteToBeginningOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_LINE character: 0 modifiers: 0]; +} + +-(void)deleteToEndOfLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_LINE character: 0 modifiers: 0]; +} + +-(void)deleteToBeginningOfParagraph: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)deleteToEndOfParagraph: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::DELETE_TO_END_OF_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)insertLineBreak: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_LINEBREAK character: 0 modifiers: 0]; +} + +-(void)insertParagraphSeparator: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::INSERT_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)selectWord: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_WORD character: 0 modifiers: 0]; +} + +-(void)selectLine: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_LINE character: 0 modifiers: 0]; +} + +-(void)selectParagraph: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_PARAGRAPH character: 0 modifiers: 0]; +} + +-(void)selectAll: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: css::awt::Key::SELECT_ALL character: 0 modifiers: 0]; +} + +-(void)cancelOperation: (id)aSender +{ + (void)aSender; + [self sendKeyInputAndReleaseToFrame: KEY_ESCAPE character: 0x1b modifiers: 0]; +} + +-(void)noop: (id)aSender +{ + (void)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; + } + } + } +} + +-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar +{ + return [self sendKeyInputAndReleaseToFrame: nKeyCode character: aChar modifiers: mpFrame->mnLastModifierFlags]; +} + +-(BOOL)sendKeyInputAndReleaseToFrame: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod +{ + return [self sendKeyToFrameDirect: nKeyCode character: aChar modifiers: nMod] || + [self sendSingleCharacter: mpLastEvent]; +} + +-(BOOL)sendKeyToFrameDirect: (sal_uInt16)nKeyCode character: (sal_Unicode)aChar modifiers: (unsigned int)nMod +{ + SolarMutexGuard aGuard; + + bool nRet = false; + if( AquaSalFrame::isAlive( mpFrame ) ) + { + SalKeyEvent aEvent; + 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; + if( AquaSalFrame::isAlive( mpFrame ) ) + mpFrame->CallCallback( SalEvent::KeyUp, &aEvent ); + } + return nRet; +} + + +-(BOOL)sendSingleCharacter: (NSEvent *)pEvent +{ + NSString* pUnmodifiedString = [pEvent charactersIgnoringModifiers]; + + if( pUnmodifiedString && [pUnmodifiedString length] == 1 ) + { + unichar keyChar = [pUnmodifiedString characterAtIndex: 0]; + sal_uInt16 nKeyCode = ImplMapCharCode( keyChar ); + if (nKeyCode == 0) + { + sal_uInt16 nOtherKeyCode = [pEvent keyCode]; + nKeyCode = ImplMapKeyCode(nOtherKeyCode); + } + if( nKeyCode != 0 ) + { + // don't send code points in the private use area + if( keyChar >= 0xf700 && keyChar < 0xf780 ) + keyChar = 0; + bool bRet = [self sendKeyToFrameDirect: nKeyCode character: keyChar modifiers: mpFrame->mnLastModifierFlags]; + mbInKeyInput = false; + + return bRet; + } + } + return NO; +} + + +// NSTextInput/NSTextInputClient protocol +- (NSArray *)validAttributesForMarkedText +{ + return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil]; +} + +- (BOOL)hasMarkedText +{ + bool 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 = true; + + 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 replacementRange:(NSRange)replacementRange +{ + (void) replacementRange; // FIXME - use it! + + SolarMutexGuard aGuard; + + 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; + if( len > 0 ) { + NSString *pString = [aString string]; + OUString aInsertString( GetOUString( pString ) ); + std::vector aInputFlags( std::max( 1, len ), ExtTextInputAttr::NONE ); + 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] = ExtTextInputAttr::Underline; + break; + case NSUnderlineStyleThick: + aInputFlags[i] = ExtTextInputAttr::Underline | ExtTextInputAttr::Highlight; + break; + case NSUnderlineStyleDouble: + aInputFlags[i] = ExtTextInputAttr::BoldUnderline; + break; + default: + aInputFlags[i] = ExtTextInputAttr::Highlight; + break; + } + } + + aInputEvent.maText = aInsertString; + aInputEvent.mnCursorPos = selRange.location; + aInputEvent.mpTextAttr = aInputFlags.data(); + mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast(&aInputEvent) ); + } else { + aInputEvent.maText.clear(); + aInputEvent.mnCursorPos = 0; + aInputEvent.mnCursorFlags = 0; + aInputEvent.mpTextAttr = nullptr; + mpFrame->CallCallback( SalEvent::ExtTextInput, static_cast(&aInputEvent) ); + mpFrame->CallCallback( SalEvent::EndExtTextInput, nullptr ); + } + mbKeyHandled= true; +} + +- (void)unmarkText +{ + mSelectedRange = mMarkedRange = NSMakeRange(NSNotFound, 0); +} + +- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange +{ + (void) aRange; + (void) actualRange; + + // FIXME - Implement + return nil; +} + +- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint +{ + (void)thePoint; + // FIXME + return 0; +} + +- (NSInteger)conversationIdentifier +{ + return reinterpret_cast(self); +} + +- (void)doCommandBySelector:(SEL)aSelector +{ + if( AquaSalFrame::isAlive( mpFrame ) ) + { + if( (mpFrame->mnICOptions & InputContextFlags::Text) && + aSelector != nullptr && [self respondsToSelector: aSelector] ) + { + [self performSelector: aSelector]; + } + else + { + [self sendSingleCharacter:mpLastEvent]; + } + } + + mbKeyHandled = true; +} + +-(void)clearLastEvent +{ + mpLastEvent = nil; +} + +- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange +{ + // FIXME - These should probably be used? + (void) aRange; + (void) actualRange; + + SolarMutexGuard aGuard; + + SalExtTextInputPosEvent aPosEvent; + mpFrame->CallCallback( SalEvent::ExtTextInputPos, static_cast(&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 reinterpret_cast(mpFrame->getNSWindow()); + //TODO: odd cast really needed for fdo#74121? +} + +-(css::accessibility::XAccessibleContext *)accessibleContext +{ + if ( !mpReferenceWrapper ) { + // some frames never become visible .. + vcl::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 ]; +} + +-(NSWindow*)windowForParent +{ + return mpFrame->getNSWindow(); +} + +-(void)registerMouseEventListener: (id)theListener +{ + mpMouseEventListener = theListener; +} + +-(void)unregisterMouseEventListener: (id)theListener +{ + (void)theListener; + mpMouseEventListener = nil; +} + +-(NSDragOperation)draggingEntered:(id )sender +{ + return [mDraggingDestinationHandler draggingEntered: sender]; +} + +-(NSDragOperation)draggingUpdated:(id )sender +{ + return [mDraggingDestinationHandler draggingUpdated: sender]; +} + +-(void)draggingExited:(id )sender +{ + [mDraggingDestinationHandler draggingExited: sender]; +} + +-(BOOL)prepareForDragOperation:(id )sender +{ + return [mDraggingDestinationHandler prepareForDragOperation: sender]; +} + +-(BOOL)performDragOperation:(id )sender +{ + return [mDraggingDestinationHandler performDragOperation: sender]; +} + +-(void)concludeDragOperation:(id )sender +{ + [mDraggingDestinationHandler concludeDragOperation: sender]; +} + +-(void)registerDraggingDestinationHandler:(id)theHandler +{ + mDraggingDestinationHandler = theHandler; +} + +-(void)unregisterDraggingDestinationHandler:(id)theHandler +{ + (void)theHandler; + mDraggingDestinationHandler = nil; +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salinst.cxx b/vcl/osx/salinst.cxx new file mode 100644 index 000000000..c1b11ebfa --- /dev/null +++ b/vcl/osx/salinst.cxx @@ -0,0 +1,987 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#import "apple_remote/RemoteMainController.h" +#include +#include + +extern "C" { +#include +} + +using namespace std; +using namespace ::com::sun::star; + +static int* gpnInit = nullptr; +static NSMenu* pDockMenu = nil; +static bool bLeftMain = false; + +namespace { + +class AquaDelayedSettingsChanged : public Idle +{ + bool mbInvalidate; + +public: + AquaDelayedSettingsChanged( bool bInvalidate ) : + mbInvalidate( bInvalidate ) + { + } + + virtual void Invoke() override + { + AquaSalInstance *pInst = GetSalData()->mpInstance; + SalFrame *pAnyFrame = pInst->anyFrame(); + if( pAnyFrame ) + pAnyFrame->CallCallback( SalEvent::SettingsChanged, nullptr ); + + if( mbInvalidate ) + { + for( auto pSalFrame : pInst->getFrames() ) + { + AquaSalFrame* pFrame = static_cast( pSalFrame ); + if( pFrame->mbShown ) + pFrame->SendPaintEvent(); + } + } + delete this; + } +}; + +} + +void AquaSalInstance::delayedSettingsChanged( bool bInvalidate ) +{ + osl::Guard< comphelper::SolarMutex > aGuard( *GetYieldMutex() ); + AquaDelayedSettingsChanged* pIdle = new AquaDelayedSettingsChanged( bInvalidate ); + pIdle->SetDebugName( "AquaSalInstance AquaDelayedSettingsChanged" ); + pIdle->Start(); +} + +// the std::list must be available before any SalData/SalInst/etc. objects are ready +std::list AquaSalInstance::aAppEventList; + +NSMenu* AquaSalInstance::GetDynamicDockMenu() +{ + if( ! pDockMenu && ! bLeftMain ) + pDockMenu = [[NSMenu alloc] initWithTitle: @""]; + return pDockMenu; +} + +bool AquaSalInstance::isOnCommandLine( const OUString& rArg ) +{ + sal_uInt32 nArgs = osl_getCommandArgCount(); + for( sal_uInt32 i = 0; i < nArgs; i++ ) + { + OUString aArg; + osl_getCommandArg( i, &aArg.pData ); + if( aArg.equals( rArg ) ) + return true; + } + return false; +} + +void AquaSalInstance::AfterAppInit() +{ + [[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 ]; +#if !HAVE_FEATURE_MACOSX_SANDBOX + // Initialize Apple Remote + GetSalData()->mpAppleRemoteMainController = [[AppleRemoteMainController alloc] init]; + + [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp + selector: @selector(applicationWillBecomeActive:) + name: @"AppleRemoteWillBecomeActive" + object: nil ]; + + [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp + selector: @selector(applicationWillResignActive:) + name: @"AppleRemoteWillResignActive" + object: nil ]; +#endif +} + +void SalAbort( const OUString& rErrorText, bool bDumpCore ) +{ + if( rErrorText.isEmpty() ) + fprintf( stderr, "Application Error " ); + else + fprintf( stderr, "%s ", + OUStringToOString( rErrorText, osl_getThreadTextEncoding() ).getStr() ); + if( bDumpCore ) + abort(); + else + _exit(1); +} + +SalYieldMutex::SalYieldMutex() + : m_aCodeBlock( nullptr ) +{ +} + +SalYieldMutex::~SalYieldMutex() +{ +} + +void SalYieldMutex::doAcquire( sal_uInt32 nLockCount ) +{ + AquaSalInstance *pInst = GetSalData()->mpInstance; + if ( pInst && pInst->IsMainThread() ) + { + if ( pInst->mbNoYieldLock ) + return; + do { + RuninmainBlock block = nullptr; + { + std::unique_lock g(m_runInMainMutex); + if (m_aMutex.tryToAcquire()) { + assert(m_aCodeBlock == nullptr); + m_wakeUpMain = false; + break; + } + // wait for doRelease() or RUNINMAIN_* to set the condition + m_aInMainCondition.wait(g, [this]() { return m_wakeUpMain; }); + m_wakeUpMain = false; + std::swap(block, m_aCodeBlock); + } + if ( block ) + { + assert( !pInst->mbNoYieldLock ); + pInst->mbNoYieldLock = true; + block(); + pInst->mbNoYieldLock = false; + Block_release( block ); + std::scoped_lock g(m_runInMainMutex); + assert(!m_resultReady); + m_resultReady = true; + m_aResultCondition.notify_all(); + } + } + while ( true ); + } + else + m_aMutex.acquire(); + ++m_nCount; + --nLockCount; + + comphelper::SolarMutex::doAcquire( nLockCount ); +} + +sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll ) +{ + AquaSalInstance *pInst = GetSalData()->mpInstance; + if ( pInst->mbNoYieldLock && pInst->IsMainThread() ) + return 1; + sal_uInt32 nCount; + { + std::scoped_lock g(m_runInMainMutex); + // read m_nCount before doRelease + bool const isReleased(bUnlockAll || m_nCount == 1); + nCount = comphelper::SolarMutex::doRelease( bUnlockAll ); + if (isReleased && !pInst->IsMainThread()) { + m_wakeUpMain = true; + m_aInMainCondition.notify_all(); + } + } + return nCount; +} + +bool SalYieldMutex::IsCurrentThread() const +{ + if ( !GetSalData()->mpInstance->mbNoYieldLock ) + return comphelper::SolarMutex::IsCurrentThread(); + else + return GetSalData()->mpInstance->IsMainThread(); +} + +// some convenience functions regarding the yield mutex, aka solar mutex + +bool ImplSalYieldMutexTryToAcquire() +{ + AquaSalInstance* pInst = GetSalData()->mpInstance; + if ( pInst ) + return pInst->GetYieldMutex()->tryToAcquire(); + else + return false; +} + +void ImplSalYieldMutexRelease() +{ + AquaSalInstance* pInst = GetSalData()->mpInstance; + if ( pInst ) + pInst->GetYieldMutex()->release(); +} + +extern "C" { +VCLPLUG_OSX_PUBLIC SalInstance* create_SalInstance() +{ + SalData* pSalData = new SalData; + + NSAutoreleasePool * pool = [ [ NSAutoreleasePool alloc ] init ]; + unlink([[NSString stringWithFormat:@"%@/Library/Saved Application State/%s.savedState/restorecount.plist", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER] UTF8String]); + unlink([[NSString stringWithFormat:@"%@/Library/Saved Application State/%s.savedState/restorecount.txt", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER] UTF8String]); + [ pool drain ]; + + // 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]; + + SAL_WARN_IF( pSalData->mpInstance != nullptr, "vcl", "more than one instance created" ); + AquaSalInstance* pInst = new AquaSalInstance; + + // init instance (only one instance in this version !!!) + pSalData->mpInstance = pInst; + // this one is for outside AquaSalInstance::Yield + SalData::ensureThreadAutoreleasePool(); + // no focus rects on NWF + ImplGetSVData()->maNWFData.mbNoFocusRects = true; + ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true; + ImplGetSVData()->maNWFData.mbCenteredTabs = true; + ImplGetSVData()->maNWFData.mnStatusBarLowerRightOffset = 10; + + return pInst; +} +} + +AquaSalInstance::AquaSalInstance() + : SalInstance(std::make_unique()) + , mnActivePrintJobs( 0 ) + , mbIsLiveResize( false ) + , mbNoYieldLock( false ) + , mbTimerProcessed( false ) +{ + maMainThread = osl::Thread::getCurrentIdentifier(); + + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mxToolkitName = OUString("osx"); +} + +AquaSalInstance::~AquaSalInstance() +{ + [NSApp stop: NSApp]; + bLeftMain = true; + if( pDockMenu ) + { + [pDockMenu release]; + pDockMenu = nil; + } +} + +void AquaSalInstance::TriggerUserEventProcessing() +{ + dispatch_async(dispatch_get_main_queue(),^{ + ImplNSAppPostEvent( AquaSalInstance::YieldWakeupEvent, NO ); + }); +} + +void AquaSalInstance::ProcessEvent( SalUserEvent aEvent ) +{ + aEvent.m_pFrame->CallCallback( aEvent.m_nEvent, aEvent.m_pData ); + maWaitingYieldCond.set(); +} + +bool AquaSalInstance::IsMainThread() const +{ + return osl::Thread::getCurrentIdentifier() == maMainThread; +} + +void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) +{ + AquaSalTimer *pTimer = static_cast( ImplGetSVData()->maSchedCtx.mpSalTimer ); + int nSubtype = [pEvent subtype]; + switch( nSubtype ) + { + case AppStartTimerEvent: + if ( pTimer ) + pTimer->handleStartTimerEvent( pEvent ); + break; + case AppExecuteSVMain: + { + int nRet = ImplSVMain(); + if (gpnInit) + *gpnInit = nRet; + [NSApp stop: NSApp]; + break; + } + case DispatchTimerEvent: + { + AquaSalInstance *pInst = GetSalData()->mpInstance; + if ( pTimer && pInst ) + pInst->mbTimerProcessed = pTimer->handleDispatchTimerEvent( pEvent ); + break; + } +#if !HAVE_FEATURE_MACOSX_SANDBOX + case AppleRemoteControlEvent: // Defined in + { + MediaCommand nCommand; + AquaSalInstance *pInst = GetSalData()->mpInstance; + bool bIsFullScreenMode = false; + + for( auto pSalFrame : pInst->getFrames() ) + { + const AquaSalFrame* pFrame = static_cast( pSalFrame ); + if ( pFrame->mbFullScreen ) + { + bIsFullScreenMode = true; + break; + } + } + + switch ([pEvent data1]) + { + case kRemoteButtonPlay: + nCommand = bIsFullScreenMode ? MediaCommand::PlayPause : MediaCommand::Play; + break; + + // kept for experimentation purpose (scheduled for future implementation) + // case kRemoteButtonMenu: nCommand = MediaCommand::Menu; break; + + case kRemoteButtonPlus: nCommand = MediaCommand::VolumeUp; break; + + case kRemoteButtonMinus: nCommand = MediaCommand::VolumeDown; break; + + case kRemoteButtonRight: nCommand = MediaCommand::NextTrack; break; + + case kRemoteButtonRight_Hold: nCommand = MediaCommand::NextTrackHold; break; + + case kRemoteButtonLeft: nCommand = MediaCommand::PreviousTrack; break; + + case kRemoteButtonLeft_Hold: nCommand = MediaCommand::Rewind; break; + + case kRemoteButtonPlay_Hold: nCommand = MediaCommand::PlayHold; break; + + case kRemoteButtonMenu_Hold: nCommand = MediaCommand::Stop; break; + + // FIXME : not detected + case kRemoteButtonPlus_Hold: + case kRemoteButtonMinus_Hold: + break; + + default: + break; + } + AquaSalFrame* pFrame = static_cast( pInst->anyFrame() ); + vcl::Window* pWindow = pFrame ? pFrame->GetWindow() : nullptr; + if( pWindow ) + { + const Point aPoint; + CommandMediaData aMediaData(nCommand); + CommandEvent aCEvt( aPoint, CommandEventId::Media, false, &aMediaData ); + NotifyEvent aNCmdEvt( MouseNotifyEvent::COMMAND, pWindow, &aCEvt ); + + if ( !ImplCallPreNotify( aNCmdEvt ) ) + pWindow->Command( aCEvt ); + } + + } + break; +#endif + + case YieldWakeupEvent: + // do nothing, fall out of Yield + break; + + default: + OSL_FAIL( "unhandled NSApplicationDefined event" ); + break; + } +} + +bool AquaSalInstance::RunInMainYield( bool bHandleAllCurrentEvents ) +{ + OSX_SALDATA_RUNINMAIN_UNION( DoYield( false, bHandleAllCurrentEvents), boolean ) + assert( false && "Don't call this from the main thread!" ); + return false; + +} + +static bool isWakeupEvent( NSEvent *pEvent ) +{ +SAL_WNODEPRECATED_DECLARATIONS_PUSH + return NSApplicationDefined == [pEvent type] + && AquaSalInstance::YieldWakeupEvent == static_cast([pEvent subtype]); +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +bool AquaSalInstance::DoYield(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; + + // first, process current user events + bool bHadEvent = DispatchUserEvents( bHandleAllCurrentEvents ); + if ( !bHandleAllCurrentEvents && bHadEvent ) + return true; + + // handle cocoa event queue + // cocoa events may be only handled in the thread the NSApp was created + if( IsMainThread() && mnActivePrintJobs == 0 ) + { + // handle available events + NSEvent* pEvent = nil; + NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime]; + mbTimerProcessed = false; + + do + { + SolarMutexReleaser aReleaser; + + pEvent = [NSApp nextEventMatchingMask: NSEventMaskAny + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; + if( pEvent ) + { + [NSApp sendEvent: pEvent]; + if ( isWakeupEvent( pEvent ) ) + continue; + bHadEvent = true; + } + + [NSApp updateWindows]; + + if ( !bHandleAllCurrentEvents || !pEvent || now < [pEvent timestamp] ) + break; + } + while( true ); + + AquaSalTimer *pTimer = static_cast( ImplGetSVData()->maSchedCtx.mpSalTimer ); + if ( !mbTimerProcessed && pTimer && pTimer->IsDirectTimeout() ) + { + pTimer->handleTimerElapsed(); + bHadEvent = true; + } + + // if we had no event yet, wait for one if requested + if( bWait && ! bHadEvent ) + { + SolarMutexReleaser aReleaser; + + pEvent = [NSApp nextEventMatchingMask: NSEventMaskAny + untilDate: [NSDate distantFuture] + inMode: NSDefaultRunLoopMode + dequeue: YES]; + if( pEvent ) + { + [NSApp sendEvent: pEvent]; + if ( !isWakeupEvent( pEvent ) ) + bHadEvent = true; + } + [NSApp updateWindows]; + } + + // collect update rectangles + for( auto pSalFrame : GetSalData()->mpInstance->getFrames() ) + { + AquaSalFrame* pFrame = static_cast( pSalFrame ); + if( pFrame->mbShown && ! pFrame->maInvalidRect.IsEmpty() ) + { + pFrame->Flush( pFrame->maInvalidRect ); + pFrame->maInvalidRect.SetEmpty(); + } + } + + if ( bHadEvent ) + maWaitingYieldCond.set(); + } + else + { + bHadEvent = RunInMainYield( bHandleAllCurrentEvents ); + if ( !bHadEvent && bWait ) + { + // #i103162# + // wait until the main thread has dispatched an event + maWaitingYieldCond.reset(); + SolarMutexReleaser aReleaser; + maWaitingYieldCond.wait(); + } + } + + // 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; + } + } + + return bHadEvent; +} + +bool AquaSalInstance::AnyInput( VclInputFlags nType ) +{ + if( nType & VclInputFlags::APPEVENT ) + { + if( ! aAppEventList.empty() ) + return true; + if( nType == VclInputFlags::APPEVENT ) + return false; + } + + OSX_INST_RUNINMAIN_UNION( AnyInput( nType ), boolean ) + + if( nType & VclInputFlags::TIMER ) + { + AquaSalTimer *pTimer = static_cast( ImplGetSVData()->maSchedCtx.mpSalTimer ); + if (pTimer && pTimer->IsTimerElapsed()) + return true; + } + + unsigned/*NSUInteger*/ nEventMask = 0; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyDownMask' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyUpMask' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftMouseDownMask' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftMouseDraggedMask' is deprecated: first deprecated in macOS 10.12 + // 'NSLeftMouseUpMask' is deprecated: first deprecated in macOS 10.12 + // 'NSMouseEnteredMask' is deprecated: first deprecated in macOS 10.12 + // 'NSMouseExitedMask' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseDownMask' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseDraggedMask' is deprecated: first deprecated in macOS 10.12 + // 'NSOtherMouseUpMask' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseDownMask' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseDraggedMask' is deprecated: first deprecated in macOS 10.12 + // 'NSRightMouseUpMask' is deprecated: first deprecated in macOS 10.12 + // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12 + // 'NSTabletPoint' is deprecated: first deprecated in macOS 10.12 + if( nType & VclInputFlags::MOUSE) + nEventMask |= + NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | + NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask | + NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask | + NSScrollWheelMask | + // NSMouseMovedMask | + NSMouseEnteredMask | NSMouseExitedMask; + if( nType & VclInputFlags::KEYBOARD) + nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; + if( nType & VclInputFlags::OTHER) + nEventMask |= NSTabletPoint | NSApplicationDefinedMask; +SAL_WNODEPRECATED_DECLARATIONS_POP + // TODO: VclInputFlags::PAINT / more VclInputFlags::OTHER + if( !bool(nType) ) + return false; + + NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil + inMode: NSDefaultRunLoopMode dequeue: NO]; + return (pEvent != nullptr); +} + +SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, SalFrameStyleFlags /*nSalFrameStyle*/ ) +{ + return nullptr; +} + +SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle ) +{ + OSX_INST_RUNINMAIN_POINTER( CreateFrame( pParent, nSalFrameStyle ), SalFrame* ) + return new AquaSalFrame( pParent, nSalFrameStyle ); +} + +void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) +{ + OSX_INST_RUNINMAIN( DestroyFrame( pFrame ) ) + delete pFrame; +} + +SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool /* bShow */ ) +{ + if ( !pParent ) + return nullptr; + + OSX_INST_RUNINMAIN_POINTER( CreateObject( pParent, pWindowData, false ), SalObject* ) + return new AquaSalObject( static_cast(pParent), pWindowData ); +} + +void AquaSalInstance::DestroyObject( SalObject* pObject ) +{ + OSX_INST_RUNINMAIN( DestroyObject( pObject ) ) + delete pObject; +} + +std::unique_ptr AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) +{ + return std::unique_ptr(new AquaSalPrinter( dynamic_cast(pInfoPrinter) )); +} + +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; + SAL_WARN_IF( nTypeCount != nNameCount, "vcl", "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 ) + { + std::unique_ptr pInfo(new SalPrinterQueueInfo); + pInfo->maPrinterName = GetOUString( pName ); + if( pType ) + pInfo->maDriver = GetOUString( pType ); + pInfo->mnStatus = PrintQueueFlags::NONE; + pInfo->mnJobs = 0; + + pList->Add( std::move(pInfo) ); + } + } +} + +void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) +{ +} + +OUString AquaSalInstance::GetDefaultPrinter() +{ + // #i113170# may not be the main thread if called from UNO API + SalData::ensureThreadAutoreleasePool(); + + if( maDefaultPrinter.isEmpty() ) + { + NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo]; + SAL_WARN_IF( !pPI, "vcl", "no print info" ); + if( pPI ) + { + NSPrinter* pPr = [pPI printer]; + SAL_WARN_IF( !pPr, "vcl", "no printer in default info" ); + if( pPr ) + { + NSString* pDefName = [pPr name]; + SAL_WARN_IF( !pDefName, "vcl", "printer has no name" ); + maDefaultPrinter = GetOUString( pDefName ); + } + } + } + return maDefaultPrinter; +} + +SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pSetupData ) +{ + // #i113170# may not be the main thread if called from UNO API + SalData::ensureThreadAutoreleasePool(); + + SalInfoPrinter* pNewInfoPrinter = nullptr; + if( pQueueInfo ) + { + pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo ); + if( pSetupData ) + pNewInfoPrinter->SetPrinterData( pSetupData ); + } + + return pNewInfoPrinter; +} + +void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) +{ + // #i113170# may not be the main thread if called from UNO API + SalData::ensureThreadAutoreleasePool(); + + delete pPrinter; +} + +OUString AquaSalInstance::GetConnectionIdentifier() +{ + return OUString(); +} + +// 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 OUString translateToExternalUrl(const OUString& internalUrl) +{ + uno::Reference< uno::XComponentContext > context( + comphelper::getProcessComponentContext()); + return uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl); +} + +// #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 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 OUString& rFileUrl, const OUString& /*rMimeType*/, const OUString& /*rDocumentService*/) +{ + // Convert file URL for external use (see above) + OUString externalUrl = translateToExternalUrl(rFileUrl); + if( externalUrl.isEmpty() ) + externalUrl = rFileUrl; + + if( !externalUrl.isEmpty() && !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(); +} + +std::shared_ptr AquaSalInstance::CreateSalBitmap() +{ + return std::make_shared(); +} + +OUString AquaSalInstance::getOSVersion() +{ + NSString * versionString = nullptr; + NSDictionary * sysVersionDict = [ NSDictionary dictionaryWithContentsOfFile: @"/System/Library/CoreServices/SystemVersion.plist" ]; + if ( sysVersionDict ) + versionString = [ sysVersionDict valueForKey: @"ProductVersion" ]; + + OUString aVersion = "Mac OS X "; + if ( versionString ) + aVersion += OUString::fromUtf8( [ versionString UTF8String ] ); + else + aVersion += "(unknown)"; + + return aVersion; +} + +CGImageRef CreateCGImage( const Image& rImage ) +{ + BitmapEx aBmpEx( rImage.GetBitmapEx() ); + Bitmap aBmp( aBmpEx.GetBitmap() ); + + if( ! aBmp || ! aBmp.ImplGetSalBitmap() ) + return nullptr; + + // simple case, no transparency + QuartzSalBitmap* pSalBmp = static_cast(aBmp.ImplGetSalBitmap().get()); + + if( ! pSalBmp ) + return nullptr; + + CGImageRef xImage = nullptr; + 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() ); + QuartzSalBitmap* pMaskBmp = static_cast(aMask.ImplGetSalBitmap().get()); + 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() == TransparentType::Bitmap ) + { + Bitmap aMask( aBmpEx.GetMask() ); + QuartzSalBitmap* pMaskBmp = static_cast(aMask.ImplGetSalBitmap().get()); + 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() == TransparentType::Color ) + { + Color aTransColor( aBmpEx.GetTransparentColor() ); + Color nTransColor( 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 lockFocusFlipped:YES]; + NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; + CGContextRef rCGContext = [pContext CGContext]; + + const CGRect aDstRect = { {0, 0}, { static_cast(aSize.Width()), static_cast(aSize.Height()) } }; + CGContextDrawImage( rCGContext, aDstRect, xImage ); + + [pImage unlockFocus]; + } + + CGImageRelease( xImage ); + + return pImage; +} + +bool AquaSalInstance::SVMainHook(int* pnInit) +{ + gpnInit = pnInit; + + OUString aExeURL, aExe; + osl_getExecutableFile( &aExeURL.pData ); + osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData ); + OString aByteExe( 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(), nullptr }; + NSApplicationMain( 1, pArgv ); +#endif + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx new file mode 100644 index 000000000..e52b14563 --- /dev/null +++ b/vcl/osx/salmenu.cxx @@ -0,0 +1,902 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +void releaseButtonEntry( AquaSalMenu::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; + } +} + +} + +const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = nullptr; + +@interface MainMenuSelector : NSObject +{ +} +-(void)showDialog: (ShowDialogId)nDialog; +-(void)showPreferences: (id)sender; +-(void)showAbout: (id)sender; +@end + +@implementation MainMenuSelector +-(void)showDialog: (ShowDialogId)nDialog +{ + if( AquaSalMenu::pCurrentMenuBar ) + { + const AquaSalFrame* pFrame = AquaSalMenu::pCurrentMenuBar->mpFrame; + if( pFrame && AquaSalFrame::isAlive( pFrame ) ) + { + pFrame->CallCallback( SalEvent::ShowDialog, reinterpret_cast(nDialog) ); + } + } + else + { + OUString aDialog; + if( nDialog == ShowDialogId::About ) + aDialog = "ABOUT"; + else if( nDialog == ShowDialogId::Preferences ) + aDialog = "PREFERENCES"; + const ApplicationEvent* pAppEvent = new ApplicationEvent( + ApplicationEvent::Type::ShowDialog, aDialog); + AquaSalInstance::aAppEventList.push_back( pAppEvent ); + } +} + +-(void)showPreferences: (id) sender +{ + (void)sender; + SolarMutexGuard aGuard; + + [self showDialog: ShowDialogId::Preferences]; +} +-(void)showAbout: (id) sender +{ + (void)sender; + SolarMutexGuard aGuard; + + [self showDialog: ShowDialogId::About]; +} +@end + +// FIXME: currently this is leaked +static MainMenuSelector* pMainMenuSelector = nil; + +static void initAppMenu() +{ + static bool bInitialized = false; + if (bInitialized) + return; + bInitialized = true; + + NSMenu* pAppMenu = nil; + NSMenuItem* pNewItem = nil; + + NSMenu* pMainMenu = [[[NSMenu alloc] initWithTitle: @"Main Menu"] autorelease]; + pNewItem = [pMainMenu addItemWithTitle: @"Application" + action: nil + keyEquivalent: @""]; + pAppMenu = [[[NSMenu alloc] initWithTitle: @"Application"] autorelease]; + [pNewItem setSubmenu: pAppMenu]; + [NSApp setMainMenu: pMainMenu]; + + pMainMenuSelector = [[MainMenuSelector alloc] init]; + + // about + NSString* pString = CreateNSString(VclResId(SV_STDTEXT_ABOUT)); + pNewItem = [pAppMenu addItemWithTitle: pString + action: @selector(showAbout:) + keyEquivalent: @""]; + [pString release]; + [pNewItem setTarget: pMainMenuSelector]; + + [pAppMenu addItem:[NSMenuItem separatorItem]]; + + // preferences + pString = CreateNSString(VclResId(SV_STDTEXT_PREFERENCES)); + pNewItem = [pAppMenu addItemWithTitle: pString + action: @selector(showPreferences:) + keyEquivalent: @","]; + [pString release]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + [pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask]; +SAL_WNODEPRECATED_DECLARATIONS_POP + [pNewItem setTarget: pMainMenuSelector]; + + [pAppMenu addItem:[NSMenuItem separatorItem]]; + + // Services item and menu + pString = CreateNSString(VclResId(SV_MENU_MAC_SERVICES)); + pNewItem = [pAppMenu addItemWithTitle: pString + action: nil + keyEquivalent: @""]; + NSMenu *servicesMenu = [[[NSMenu alloc] initWithTitle:@"Services"] autorelease]; + [pNewItem setSubmenu: servicesMenu]; + [NSApp setServicesMenu: servicesMenu]; + + [pAppMenu addItem:[NSMenuItem separatorItem]]; + + // Hide Application + pString = CreateNSString(VclResId(SV_MENU_MAC_HIDEAPP)); + [pAppMenu addItemWithTitle: pString + action:@selector(hide:) + keyEquivalent:@"h"]; + [pString release]; + + // Hide Others + pString = CreateNSString(VclResId(SV_MENU_MAC_HIDEALL)); + [pAppMenu addItemWithTitle: pString + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"]; + [pString release]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + [pNewItem setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask]; +SAL_WNODEPRECATED_DECLARATIONS_POP + + // Show All + pString = CreateNSString(VclResId(SV_MENU_MAC_SHOWALL)); + [pAppMenu addItemWithTitle: pString + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [pString release]; + + [pAppMenu addItem:[NSMenuItem separatorItem]]; + + // Quit + pString = CreateNSString(VclResId(SV_MENU_MAC_QUITAPP)); + [pAppMenu addItemWithTitle: pString + action:@selector(terminate:) + keyEquivalent:@"q"]; + [pString release]; +} + +std::unique_ptr AquaSalInstance::CreateMenu( bool bMenuBar, Menu* pVCLMenu ) +{ + initAppMenu(); + + AquaSalMenu *pAquaSalMenu = new AquaSalMenu( bMenuBar ); + pAquaSalMenu->mpVCLMenu = pVCLMenu; + + return std::unique_ptr(pAquaSalMenu); +} + +std::unique_ptr AquaSalInstance::CreateMenuItem( const SalItemParams & rItemData ) +{ + AquaSalMenuItem *pSalMenuItem = new AquaSalMenuItem( &rItemData ); + + return std::unique_ptr(pSalMenuItem); +} + +/* + * AquaSalMenu + */ + +AquaSalMenu::AquaSalMenu( bool bMenuBar ) : + mbMenuBar( bMenuBar ), + mpMenu( nil ), + mpFrame( nullptr ), + mpParentSalMenu( nullptr ) +{ + if( ! mbMenuBar ) + { + mpMenu = [[SalNSMenu alloc] initWithMenu: this]; + [mpMenu setDelegate: reinterpret_cast< id >(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(mpFrame)->mpMenu = nullptr; + + // 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(mpMenu) setSalMenu: nullptr]; + /* #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]; + } + } +} + +bool AquaSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const tools::Rectangle& rRect, FloatWinPopupFlags nFlags) +{ + // set offsets for positioning + const float offset = 9.0; + + // get the pointers + AquaSalFrame * pParentAquaSalFrame = static_cast(pWin->ImplGetWindowImpl()->mpRealParent->ImplGetFrame()); + NSWindow* pParentNSWindow = pParentAquaSalFrame->mpNSWindow; + NSView* pParentNSView = [pParentNSWindow contentView]; + NSView* pPopupNSView = static_cast(pWin->ImplGetWindow()->ImplGetFrame())->mpNSView; + NSRect popupFrame = [pPopupNSView frame]; + + // create frame rect + NSRect displayPopupFrame = NSMakeRect( rRect.Left()+(offset-1), rRect.Top()+(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 + sal_uInt16 nArrangeIndex; + pWin->SetPosPixel( FloatingWindow::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: mpMenu]; + [pPopUpButtonCell selectItem:nil]; + [AquaA11yWrapper setPopupMenuOpen: YES]; + [pPopUpButtonCell performClickWithFrame:displayPopupFrame inView:pParentNSView]; + [pPopUpButtonCell release]; + [AquaA11yWrapper setPopupMenuOpen: NO]; + + return true; +} + +int AquaSalMenu::getItemIndexByPos( sal_uInt16 nPos ) const +{ + int nIndex = 0; + if( nPos == MENU_APPEND ) + nIndex = [mpMenu numberOfItems]; + else + nIndex = sal::static_int_cast( 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 : nullptr; +} + +void AquaSalMenu::unsetMainMenu() +{ + pCurrentMenuBar = nullptr; + + // remove items from main menu + NSMenu* pMenu = [NSApp mainMenu]; + for( int nItems = [pMenu numberOfItems]; nItems > 1; nItems-- ) + [pMenu removeItemAtIndex: 1]; +} + +void AquaSalMenu::setMainMenu() +{ + SAL_WARN_IF( !mbMenuBar, "vcl", "setMainMenu on non menubar" ); + if( mbMenuBar ) + { + if( pCurrentMenuBar != this ) + { + unsetMainMenu(); + // insert our items + for( std::vector::size_type 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 == nullptr ) + 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 == nullptr ) + setDefaultMenu(); + + return; + } + } +} + +bool AquaSalMenu::VisibleMenuBar() +{ + return true; +} + +void AquaSalMenu::SetFrame( const SalFrame *pFrame ) +{ + mpFrame = static_cast(pFrame); +} + +void AquaSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos ) +{ + AquaSalMenuItem *pAquaSalMenuItem = static_cast(pSalMenuItem); + + pAquaSalMenuItem->mpParentMenu = this; + DBG_ASSERT( pAquaSalMenuItem->mpVCLMenu == nullptr || + pAquaSalMenuItem->mpVCLMenu == mpVCLMenu || + mpVCLMenu == nullptr, + "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 + { + OSL_FAIL( "invalid item index in insert" ); + return; + } + + if( ! mbMenuBar || pCurrentMenuBar == this ) + [mpMenu insertItem: pAquaSalMenuItem->mpMenuItem atIndex: getItemIndexByPos(nPos)]; +} + +void AquaSalMenu::RemoveItem( unsigned nPos ) +{ + AquaSalMenuItem* pRemoveItem = nullptr; + 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 + { + OSL_FAIL( "invalid item index in remove" ); + return; + } + + pRemoveItem->mpParentMenu = nullptr; + + if( ! mbMenuBar || pCurrentMenuBar == this ) + [mpMenu removeItemAtIndex: getItemIndexByPos(nPos)]; +} + +void AquaSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned /*nPos*/ ) +{ + AquaSalMenuItem *pAquaSalMenuItem = static_cast(pSalMenuItem); + AquaSalMenu *subAquaSalMenu = static_cast(pSubMenu); + + if (subAquaSalMenu) + { + pAquaSalMenuItem->mpSubMenu = subAquaSalMenu; + if( subAquaSalMenu->mpParentSalMenu == nullptr ) + { + 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 = nullptr; + } + pAquaSalMenuItem->mpSubMenu = nullptr; + [pAquaSalMenuItem->mpMenuItem setSubmenu: nil]; + } +} + +void AquaSalMenu::CheckItem( unsigned nPos, bool bCheck ) +{ + if( nPos < maItems.size() ) + { + NSMenuItem* pItem = maItems[nPos]->mpMenuItem; + [pItem setState: bCheck ? NSControlStateValueOn : NSControlStateValueOff]; + } +} + +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( 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 OUString& i_rText ) +{ + if (!i_pSalMenuItem) + return; + + AquaSalMenuItem *pAquaSalMenuItem = static_cast(i_pSalMenuItem); + + // Delete mnemonics + OUString aText = i_rText.replaceAll("~", ""); + + /* #i90015# until there is a correct solution + strip out any appended (.*) in menubar entries + */ + if( mbMenuBar ) + { + sal_Int32 nPos = aText.lastIndexOf( '(' ); + if( nPos != -1 ) + { + sal_Int32 nPos2 = aText.indexOf( ')' ); + if( nPos2 != -1 ) + aText = aText.replaceAt( nPos, nPos2-nPos+1, "" ); + } + } + + if (aText.endsWith("...", &aText)) + aText += u"\u2026"; + + 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 vcl::KeyCode& rKeyCode, const OUString& /*rKeyName*/ ) +{ + sal_uInt16 nModifier; + sal_Unicode nCommandKey = 0; + + sal_uInt16 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; + case KEY_SEMICOLON: + nCommandKey=';'; + break; + case KEY_BACKSPACE: + nCommandKey=u'\x232b'; + break; + case KEY_PAGEUP: + nCommandKey=u'\x21de'; + break; + case KEY_PAGEDOWN: + nCommandKey=u'\x21df'; + break; + case KEY_UP: + nCommandKey=u'\x21e1'; + break; + case KEY_DOWN: + nCommandKey=u'\x21e3'; + break; + case KEY_RETURN: + nCommandKey=u'\x21a9'; + break; + case KEY_BRACKETLEFT: + nCommandKey='['; + break; + case KEY_BRACKETRIGHT: + nCommandKey=']'; + break; + } + } + } + else // not even a code ? nonsense -> ignore + return; + + SAL_WARN_IF( !nCommandKey, "vcl", "unmapped accelerator key" ); + + nModifier=rKeyCode.GetModifier(); + + // should always use the command key + int nItemModifier = 0; + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + 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; +SAL_WNODEPRECATED_DECLARATIONS_POP + + AquaSalMenuItem *pAquaSalMenuItem = static_cast(pSalMenuItem); + NSString* pString = CreateNSString( OUString( &nCommandKey, 1 ) ); + [pAquaSalMenuItem->mpMenuItem setKeyEquivalent: pString]; + [pAquaSalMenuItem->mpMenuItem setKeyEquivalentModifierMask: nItemModifier]; + if (pString) + [pString release]; +} + +void AquaSalMenu::GetSystemMenuData( SystemMenuData* ) +{ +} + +AquaSalMenu::MenuBarButtonEntry* AquaSalMenu::findButtonItem( sal_uInt16 i_nItemId ) +{ + for( size_t i = 0; i < maButtons.size(); ++i ) + { + if( maButtons[i].maButton.mnId == i_nItemId ) + return &maButtons[i]; + } + return nullptr; +} + +void AquaSalMenu::statusLayout() +{ + if( GetSalData()->mpStatusItem ) + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'view' is deprecated: first deprecated in macOS 10.14 - Use the standard button + // property instead" + NSView* pNSView = [GetSalData()->mpStatusItem view]; +SAL_WNODEPRECATED_DECLARATIONS_POP + if( [pNSView isMemberOfClass: [OOStatusItemView class]] ) // well of course it is + [static_cast(pNSView) layout]; + else + OSL_FAIL( "someone stole our status view" ); + } +} + +bool AquaSalMenu::AddMenuBarButton( const SalMenuButtonItem& i_rNewItem ) +{ + if( ! mbMenuBar ) + 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( sal_uInt16 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.data()) ); + } + + if( pCurrentMenuBar == this ) + statusLayout(); +} + +tools::Rectangle AquaSalMenu::GetMenuBarButtonRectPixel( sal_uInt16 i_nItemId, SalFrame* i_pReferenceFrame ) +{ + if( ! i_pReferenceFrame || ! AquaSalFrame::isAlive( static_cast(i_pReferenceFrame) ) ) + return tools::Rectangle(); + + MenuBarButtonEntry* pEntry = findButtonItem( i_nItemId ); + + if( ! pEntry ) + return tools::Rectangle(); + + NSStatusItem* pItem = SalData::getStatusItem(); + if( ! pItem ) + return tools::Rectangle(); + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'view' is deprecated: first deprecated in macOS 10.14 - Use the standard button property + // instead" + NSView* pNSView = [pItem view]; +SAL_WNODEPRECATED_DECLARATIONS_POP + if( ! pNSView ) + return tools::Rectangle(); + NSWindow* pNSWin = [pNSView window]; + if( ! pNSWin ) + return tools::Rectangle(); + + NSRect aRect = [pNSWin convertRectToScreen:[pNSWin frame]]; + + // make coordinates relative to reference frame + static_cast(i_pReferenceFrame)->CocoaToVCL( aRect.origin ); + aRect.origin.x -= i_pReferenceFrame->maGeometry.nX; + aRect.origin.y -= i_pReferenceFrame->maGeometry.nY + aRect.size.height; + + return tools::Rectangle( Point(static_cast(aRect.origin.x), + static_cast(aRect.origin.y) + ), + Size( static_cast(aRect.size.width), + static_cast(aRect.size.height) + ) + ); +} + +/* + * SalMenuItem + */ + +AquaSalMenuItem::AquaSalMenuItem( const SalItemParams* pItemData ) : + mnId( pItemData->nId ), + mpVCLMenu( pItemData->pMenu ), + mpParentMenu( nullptr ), + mpSubMenu( nullptr ), + mpMenuItem( nil ) +{ + if (pItemData->eType == MenuItemType::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]; + + // peel mnemonics because on mac there are no such things for menu items + NSString* pString = CreateNSString( pItemData->aText.replaceAll( "~", "" ) ); + if (pString) + { + [mpMenuItem setTitle: pString]; + [pString release]; + } + // anything but a separator should set a menu to dispatch to + SAL_WARN_IF( !mpVCLMenu, "vcl", "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]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx new file mode 100644 index 000000000..6ec959ed2 --- /dev/null +++ b/vcl/osx/salnativewidgets.cxx @@ -0,0 +1,1141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "cuidraw.hxx" + +// presentation of native widgets consists of two important methods: + +// AquaSalGraphics::getNativeControlRegion to determine native rectangle in pixels to draw the widget +// AquaSalGraphics::drawNativeControl to do the drawing operation itself + +// getNativeControlRegion has to calculate a content rectangle within it is safe to draw the widget. Furthermore a bounding rectangle +// has to be calculated by getNativeControlRegion to consider adornments like a focus rectangle. As drawNativeControl uses Carbon +// API calls, all widgets are drawn without text. Drawing of text is done separately by VCL on top of graphical Carbon widget +// representation. drawNativeControl is called by VCL using content rectangle determined by getNativeControlRegion. + +// FIXME: when calculation bounding rectangle larger then content rectangle, text displayed by VCL will become misaligned. To avoid +// misalignment bounding rectangle and content rectangle are calculated equally including adornments. Reduction of size for content +// is done by drawNativeControl subsequently. Only exception is editbox: As other widgets have distinct ControlPart::SubEdit control +// parts, editbox bounding rectangle and content rectangle are both calculated to reflect content area. Extending size for +// adornments is done by drawNativeControl subsequently. + +#if !HAVE_FEATURE_MACOSX_SANDBOX + +@interface NSWindow(CoreUIRendererPrivate) ++ (CUIRendererRef)coreUIRenderer; +@end + +#endif + +static HIRect ImplGetHIRectFromRectangle(tools::Rectangle aRect) +{ + HIRect aHIRect; + aHIRect.origin.x = static_cast(aRect.Left()); + aHIRect.origin.y = static_cast(aRect.Top()); + aHIRect.size.width = static_cast(aRect.GetWidth()); + aHIRect.size.height = static_cast(aRect.GetHeight()); + return aHIRect; +} + +static ThemeButtonValue ImplGetButtonValue(ButtonValue aButtonValue) +{ + switch (aButtonValue) + { + case ButtonValue::On: + return kThemeButtonOn; + break; + case ButtonValue::Off: + case ButtonValue::DontKnow: + return kThemeButtonOff; + break; + case ButtonValue::Mixed: + default: + return kThemeButtonMixed; + break; + } +} + +static bool AquaGetScrollRect(/* TODO: int nScreen, */ + ControlPart nPart, const tools::Rectangle &rControlRect, tools::Rectangle &rResultRect) +{ + bool bRetVal = true; + rResultRect = rControlRect; + switch (nPart) + { + case ControlPart::ButtonUp: + rResultRect.SetBottom(rResultRect.Top()); + break; + case ControlPart::ButtonDown: + rResultRect.SetTop(rResultRect.Bottom()); + break; + case ControlPart::ButtonLeft: + rResultRect.SetRight(rResultRect.Left()); + break; + case ControlPart::ButtonRight: + rResultRect.SetLeft(rResultRect.Right()); + break; + case ControlPart::TrackHorzArea: + case ControlPart::TrackVertArea: + case ControlPart::ThumbHorz: + case ControlPart::ThumbVert: + case ControlPart::TrackHorzLeft: + case ControlPart::TrackHorzRight: + case ControlPart::TrackVertUpper: + case ControlPart::TrackVertLower: + break; + default: + bRetVal = false; + } + return bRetVal; +} + +bool AquaSalGraphics::isNativeControlSupported(ControlType nType, ControlPart nPart) +{ + // native controls are now defaults. If you want to disable native controls, set the environment variable SAL_NO_NWF to + // something and VCL controls will be used as default again. + + switch (nType) + { + case ControlType::Pushbutton: + case ControlType::Radiobutton: + case ControlType::Checkbox: + case ControlType::ListNode: + if (nPart == ControlPart::Entire) + return true; + break; + case ControlType::Scrollbar: + if (nPart == ControlPart::DrawBackgroundHorz || nPart == ControlPart::DrawBackgroundVert + || nPart == ControlPart::Entire || nPart == ControlPart::HasThreeButtons) + return true; + break; + case ControlType::Slider: + if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea) + return true; + break; + case ControlType::Editbox: + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) + return true; + break; + case ControlType::MultilineEditbox: + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) + return true; + break; + case ControlType::Spinbox: + if (nPart == ControlPart::Entire || nPart == ControlPart::AllButtons || nPart == ControlPart::HasBackgroundTexture) + return true; + break; + case ControlType::SpinButtons: + return false; + break; + case ControlType::Combobox: + if (nPart == ControlPart::Entire || nPart == ControlPart::HasBackgroundTexture) + return true; + break; + case ControlType::Listbox: + if (nPart == ControlPart::Entire || nPart == ControlPart::ListboxWindow || nPart == ControlPart::HasBackgroundTexture + || nPart == ControlPart::SubEdit) + return true; + break; + case ControlType::TabItem: + case ControlType::TabPane: + case ControlType::TabBody: + if (nPart == ControlPart::Entire || nPart == ControlPart::TabsDrawRtl || nPart == ControlPart::HasBackgroundTexture) + return true; + break; + case ControlType::Toolbar: + if (nPart == ControlPart::Entire || nPart == ControlPart::DrawBackgroundHorz + || nPart == ControlPart::DrawBackgroundVert) + return true; + break; + case ControlType::WindowBackground: + if (nPart == ControlPart::BackgroundWindow || nPart == ControlPart::BackgroundDialog) + return true; + break; + case ControlType::Menubar: + if (nPart == ControlPart::Entire) + return true; + break; + case ControlType::Tooltip: + if (nPart == ControlPart::Entire) + return true; + break; + case ControlType::MenuPopup: + if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::MenuItemCheckMark + || nPart == ControlPart::MenuItemRadioMark) + return true; + break; + case ControlType::Progress: + case ControlType::IntroProgress: + if (nPart == ControlPart::Entire) + return true; + break; + case ControlType::Frame: + if (nPart == ControlPart::Border) + return true; + break; + case ControlType::ListNet: + if (nPart == ControlPart::Entire) + return true; + break; + default: + break; + } + return false; +} + +bool AquaSalGraphics::hitTestNativeControl(ControlType nType, ControlPart nPart, const tools::Rectangle &rControlRegion, + const Point &rPos, bool& rIsInside) +{ + if (nType == ControlType::Scrollbar) + { + tools::Rectangle aRect; + bool bValid = AquaGetScrollRect(/* TODO: int nScreen, */ + nPart, rControlRegion, aRect); + rIsInside = bValid && aRect.IsInside(rPos); + return bValid; + } + return false; +} + +UInt32 AquaSalGraphics::getState(ControlState nState) +{ + + // there are non key windows which are childs of key windows, e.g. autofilter configuration dialog or sidebar dropdown dialogs. + // To handle these windows correctly, parent frame's key window state is considered here additionally. + + const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow] + || mpFrame->mpParent == nullptr || [mpFrame->mpParent->getNSWindow() isKeyWindow]; + if (!(nState & ControlState::ENABLED) || !bDrawActive) + { + return kThemeStateInactive; + } + if (nState & ControlState::PRESSED) + return kThemeStatePressed; + return kThemeStateActive; +} + +UInt32 AquaSalGraphics::getTrackState(ControlState nState) +{ + const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; + if (!(nState & ControlState::ENABLED) || !bDrawActive) + return kThemeTrackInactive; + return kThemeTrackActive; +} + +bool AquaSalGraphics::drawNativeControl(ControlType nType, + ControlPart nPart, + const tools::Rectangle &rControlRegion, + ControlState nState, + const ImplControlValue &aValue, + const OUString &, + const Color&) +{ + bool bOK = false; + if (!CheckContext()) + return false; + maContextHolder.saveState(); + tools::Rectangle buttonRect = rControlRegion; + HIRect rc = ImplGetHIRectFromRectangle(buttonRect); + switch (nType) + { + case ControlType::Toolbar: + { +#if HAVE_FEATURE_MACOSX_SANDBOX + HIThemeMenuItemDrawInfo aMenuItemDrawInfo; + aMenuItemDrawInfo.version = 0; + aMenuItemDrawInfo.state = kThemeMenuActive; + aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; + HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); +#else + if (rControlRegion.Top() == 0 && nPart == ControlPart::DrawBackgroundHorz) + { + const bool bDrawActive = mpFrame == nullptr || [mpFrame->getNSWindow() isKeyWindow]; + CGFloat unifiedHeight = rControlRegion.GetHeight(); + CGRect drawRect = CGRectMake(rControlRegion.Left(), rControlRegion.Top(), + rControlRegion.GetWidth(), rControlRegion.GetHeight()); + CUIDraw([NSWindow coreUIRenderer], drawRect, maContextHolder.get(), + reinterpret_cast([NSDictionary dictionaryWithObjectsAndKeys: + @"kCUIWidgetWindowFrame", + @"widget", + @"regularwin", + @"windowtype", + (bDrawActive ? @"normal" : @"inactive"), + @"state", + [NSNumber numberWithDouble:unifiedHeight], + @"kCUIWindowFrameUnifiedTitleBarHeightKey", + [NSNumber numberWithBool:NO], + @"kCUIWindowFrameDrawTitleSeparatorKey", + [NSNumber numberWithBool:YES], + @"is.flipped", + nil]), + nil); + } + else + { + HIThemeMenuItemDrawInfo aMenuItemDrawInfo; + aMenuItemDrawInfo.version = 0; + aMenuItemDrawInfo.state = kThemeMenuActive; + aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; + HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + } +#endif + bOK = true; + } + break; + case ControlType::WindowBackground: + { + HIThemeBackgroundDrawInfo aThemeBackgroundInfo; + aThemeBackgroundInfo.version = 0; + aThemeBackgroundInfo.state = getState(nState); + aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive; + + // 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, maContextHolder.get(), kHIThemeOrientationNormal); + CGContextFillRect(maContextHolder.get(), rc); + bOK = true; + } + break; + case ControlType::Tooltip: + { + HIThemeBackgroundDrawInfo aThemeBackgroundInfo; + aThemeBackgroundInfo.version = 0; + aThemeBackgroundInfo.state = getState(nState); + aThemeBackgroundInfo.kind = kThemeBrushAlertBackgroundActive; + rc.size.width += 2; + rc.size.height += 2; + HIThemeApplyBackground(&rc, &aThemeBackgroundInfo, maContextHolder.get(), kHIThemeOrientationNormal); + CGContextFillRect(maContextHolder.get(), rc); + bOK = true; + } + break; + case ControlType::Menubar: + case ControlType::MenuPopup: + if (nPart == ControlPart::Entire || nPart == ControlPart::MenuItem || nPart == ControlPart::HasBackgroundTexture) + { + + // 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; + + // grey theme when the item is selected is drawn here. + + aMenuItemDrawInfo.itemType = kThemeMenuItemPlain; + if ((nPart == ControlPart::MenuItem) && (nState & ControlState::SELECTED)) + + // 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,maContextHolder.get(), kHIThemeOrientationNormal); + + // repaints the item either blue (selected) and/or grey (active only) + + HIThemeDrawMenuItem(&rc, &rc, &aMenuItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, &rc); + bOK = true; + } + else if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark) + { + + // checked, else it is not displayed (see vcl/source/window/menu.cxx) + + if (nState & ControlState::PRESSED) + { + HIThemeTextInfo aTextInfo; + aTextInfo.version = 0; + aTextInfo.state = (nState & ControlState::ENABLED) ? kThemeStateInactive: kThemeStateActive; + aTextInfo.fontID = kThemeMenuItemMarkFont; + aTextInfo.horizontalFlushness = kHIThemeTextHorizontalFlushCenter; + aTextInfo.verticalFlushness = kHIThemeTextVerticalFlushTop; + aTextInfo.options = kHIThemeTextBoxOptionNone; + aTextInfo.truncationPosition = kHIThemeTextTruncationNone; + + // aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone item highlighted + + if (nState & ControlState::SELECTED) aTextInfo.state = kThemeStatePressed; + UniChar mark=(nPart == ControlPart::MenuItemCheckMark) ? kCheckUnicode: kBulletUnicode; + CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull); + HIThemeDrawTextBox(cfString, &rc, &aTextInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (cfString) + CFRelease(cfString); + bOK = true; + } + } + break; + case ControlType::Pushbutton: + { + + // FIXME: instead of use a value, VCL can retrieve correct values on the fly (to be implemented) + + HIThemeButtonDrawInfo aPushInfo; + aPushInfo.version = 0; + + // no animation + + aPushInfo.animation.time.start = 0; + aPushInfo.animation.time.current = 0; + PushButtonValue const *pPBVal = aValue.getType() == ControlType::Pushbutton ? + static_cast(&aValue) : nullptr; + int nPaintHeight = static_cast(rc.size.height); + if (pPBVal && pPBVal->mbBevelButton) + { + aPushInfo.kind = kThemeRoundedBevelButton; + } + else if (rc.size.height <= PUSH_BUTTON_NORMAL_HEIGHT) + { + aPushInfo.kind = kThemePushButtonMini; + nPaintHeight = PUSH_BUTTON_SMALL_HEIGHT; + } + else if ((pPBVal && pPBVal->mbSingleLine) || rc.size.height < PUSH_BUTTON_NORMAL_HEIGHT * 3 / 2) + { + aPushInfo.kind = kThemePushButtonNormal; + nPaintHeight = PUSH_BUTTON_NORMAL_HEIGHT; + + // avoid clipping when focused + + rc.origin.x += FOCUS_RING_WIDTH / 2; + rc.size.width -= FOCUS_RING_WIDTH; + } + else + aPushInfo.kind = kThemeBevelButton; + + // translate the origin for controls with fixed paint height so content ends up somewhere sensible + + rc.origin.y += (rc.size.height - nPaintHeight) / 2; + aPushInfo.state = getState(nState); + aPushInfo.value = ImplGetButtonValue(aValue.getTristateVal()); + aPushInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aPushInfo.adornment |= kThemeAdornmentFocus; + HIThemeDrawButton(&rc, &aPushInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::Radiobutton: + case ControlType::Checkbox: + { + HIThemeButtonDrawInfo aInfo; + aInfo.version = 0; + switch (nType) + { + case ControlType::Radiobutton: + if (rc.size.width >= RADIO_BUTTON_SMALL_SIZE) + aInfo.kind = kThemeRadioButton; + else + aInfo.kind = kThemeSmallRadioButton; + break; + case ControlType::Checkbox: + if (rc.size.width >= CHECKBOX_SMALL_SIZE) + aInfo.kind = kThemeCheckBox; + else + aInfo.kind = kThemeSmallCheckBox; + break; + default: + break; + } + aInfo.state = getState(nState); + ButtonValue aButtonValue = aValue.getTristateVal(); + aInfo.value = ImplGetButtonValue(aButtonValue); + aInfo.adornment = (nState & ControlState::DEFAULT) ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = RADIO_BUTTON_SMALL_SIZE; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::ListNode: + { + ButtonValue aButtonValue = aValue.getTristateVal(); + 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; + break; + case ButtonValue::Off: + if (AllSettings::GetLayoutRTL()) + aInfo.value = kThemeDisclosureLeft; + break; + case ButtonValue::DontKnow: + default: + break; + } + HIThemeDrawButton(&rc, &aInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::Progress: + case ControlType::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(rc.size.width); + aTrackInfo.value = nProgressWidth; + aTrackInfo.reserved = 0; + aTrackInfo.attributes = kThemeTrackHorizontal; + if (AllSettings::GetLayoutRTL()) + aTrackInfo.attributes |= kThemeTrackRightToLeft; + aTrackInfo.enableState = getTrackState(nState); + + // the intro bitmap never gets key anyway; we want to draw that enabled + + if (nType == ControlType::IntroProgress) + aTrackInfo.enableState = kThemeTrackActive; + aTrackInfo.filler1 = 0; + aTrackInfo.trackInfo.progress.phase = static_cast(CFAbsoluteTimeGetCurrent() * 10.0); + HIThemeDrawTrack(&aTrackInfo, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + break; + case ControlType::Slider: + { + const SliderValue *pSliderVal = static_cast(&aValue); + HIThemeTrackDrawInfo aTrackDraw; + aTrackDraw.kind = kThemeSliderMedium; + if (nPart == ControlPart::TrackHorzArea || nPart == ControlPart::TrackVertArea) + { + aTrackDraw.bounds = rc; + aTrackDraw.min = pSliderVal->mnMin; + aTrackDraw.max = pSliderVal->mnMax; + aTrackDraw.value = pSliderVal->mnCur; + aTrackDraw.reserved = 0; + aTrackDraw.attributes = kThemeTrackShowThumb; + if (nPart == ControlPart::TrackHorzArea) + aTrackDraw.attributes |= kThemeTrackHorizontal; + aTrackDraw.enableState = (nState & ControlState::ENABLED) ? kThemeTrackActive : kThemeTrackInactive; + SliderTrackInfo aSlideInfo; + aSlideInfo.thumbDir = kThemeThumbUpward; + aSlideInfo.pressState = 0; + aTrackDraw.trackInfo.slider = aSlideInfo; + HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + } + break; + case ControlType::Scrollbar: + { + const ScrollbarValue *pScrollbarVal = (aValue.getType() == ControlType::Scrollbar) + ? static_cast(&aValue) : nullptr; + if (nPart == ControlPart::DrawBackgroundVert || nPart == ControlPart::DrawBackgroundHorz) + { + HIThemeTrackDrawInfo aTrackDraw; + aTrackDraw.kind = kThemeMediumScrollBar; + 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 == ControlPart::DrawBackgroundHorz) + aTrackDraw.attributes |= kThemeTrackHorizontal; + aTrackDraw.enableState = getTrackState(nState); + ScrollBarTrackInfo aScrollInfo; + aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize; + aScrollInfo.pressState = 0; + if (pScrollbarVal->mnButton1State & ControlState::ENABLED) + if (pScrollbarVal->mnButton1State & ControlState::PRESSED) + aScrollInfo.pressState = kThemeTopOutsideArrowPressed; + if (pScrollbarVal->mnButton2State & ControlState::ENABLED ) + if (pScrollbarVal->mnButton2State & ControlState::PRESSED ) + aScrollInfo.pressState = kThemeBottomOutsideArrowPressed; + if ( pScrollbarVal->mnThumbState & ControlState::ENABLED) + if (pScrollbarVal->mnThumbState & ControlState::PRESSED) + aScrollInfo.pressState = kThemeThumbPressed; + aTrackDraw.trackInfo.scrollbar = aScrollInfo; + HIThemeDrawTrack(&aTrackDraw, nullptr, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + } + break; + case ControlType::TabPane: + { + HIThemeTabPaneDrawInfo aTabPaneDrawInfo; + aTabPaneDrawInfo.version = 1; + aTabPaneDrawInfo.state = kThemeStateActive; + aTabPaneDrawInfo.direction = kThemeTabNorth; + aTabPaneDrawInfo.size = kHIThemeTabSizeNormal; + aTabPaneDrawInfo.kind = kHIThemeTabKindNormal; + + // border is outside the rect rc for Carbon but for VCL it should be inside + + rc.origin.x += 1; + rc.origin.y -= TAB_HEIGHT / 2; + rc.size.height += TAB_HEIGHT / 2; + rc.size.width -= 2; + HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + break; + case ControlType::TabItem: + { + HIThemeTabDrawInfo aTabItemDrawInfo; + aTabItemDrawInfo.version = 1; + aTabItemDrawInfo.style = kThemeTabNonFront; + aTabItemDrawInfo.direction = kThemeTabNorth; + aTabItemDrawInfo.size = kHIThemeTabSizeNormal; + aTabItemDrawInfo.adornment = kHIThemeTabAdornmentTrailingSeparator; + if (nState & ControlState::SELECTED) + aTabItemDrawInfo.style = kThemeTabFront; + if(nState & ControlState::FOCUSED) + aTabItemDrawInfo.adornment |= kHIThemeTabAdornmentFocus; + + // first, last or middle tab + + aTabItemDrawInfo.position = kHIThemeTabPositionMiddle; + TabitemValue const * pTabValue = static_cast(&aValue); + TabitemFlags nAlignment = pTabValue->mnAlignment; + + // TabitemFlags::LeftAligned (and TabitemFlags::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 TabitemFlags::FirstInGroup (and TabitemFlags::LastInGroup) because when the + // line width is different from window width, there may not be TabitemFlags::RightAligned + + if (((nAlignment & TabitemFlags::LeftAligned) && (nAlignment & TabitemFlags::RightAligned)) + || ((nAlignment & TabitemFlags::FirstInGroup) && (nAlignment & TabitemFlags::LastInGroup))) + aTabItemDrawInfo.position = kHIThemeTabPositionOnly; + else if ((nAlignment & TabitemFlags::LeftAligned) || (nAlignment & TabitemFlags::FirstInGroup)) + aTabItemDrawInfo.position = kHIThemeTabPositionFirst; + else if ((nAlignment & TabitemFlags::RightAligned) || (nAlignment & TabitemFlags::LastInGroup)) + aTabItemDrawInfo.position = kHIThemeTabPositionLast; + + // support for RTL (see issue 79748) + + if (AllSettings::GetLayoutRTL()) { + if (aTabItemDrawInfo.position == kHIThemeTabPositionFirst) + aTabItemDrawInfo.position = kHIThemeTabPositionLast; + else if (aTabItemDrawInfo.position == kHIThemeTabPositionLast) + aTabItemDrawInfo.position = kHIThemeTabPositionFirst; + } + rc.size.width += VCL_TAB_TEXT_SEPARATOR; + rc.origin.x -= 1; + HIThemeDrawTab(&rc, &aTabItemDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK=true; + } + break; + case ControlType::Editbox: + case ControlType::MultilineEditbox: + { + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width += 2 * EDITBOX_INSET_MARGIN; + if (nType == ControlType::Editbox) + rc.size.height = EDITBOX_HEIGHT; + else + rc.size.height += 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + rc.origin.x -= EDITBOX_INSET_MARGIN; + rc.origin.y -= EDITBOX_INSET_MARGIN; + + // fill a white background, because HIThemeDrawFrame only draws the border + + CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + break; + case ControlType::Combobox: + if (nPart == ControlPart::HasBackgroundTexture || nPart == ControlPart::Entire) + { + HIThemeButtonDrawInfo aComboInfo; + aComboInfo.version = 0; + aComboInfo.kind = kThemeComboBox; + aComboInfo.state = getState(nState); + aComboInfo.value = kThemeButtonOn; + aComboInfo.adornment = kThemeAdornmentNone; + if (nState & ControlState::FOCUSED) + aComboInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = COMBOBOX_HEIGHT; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aComboInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + } + break; + case ControlType::Listbox: + switch (nPart) + { + case ControlPart::Entire: + case ControlPart::ButtonDown: + HIThemeButtonDrawInfo aListInfo; + aListInfo.version = 0; + aListInfo.kind = kThemePopupButton; + aListInfo.state = getState(nState); + aListInfo.value = kThemeButtonOn; + aListInfo.adornment = kThemeAdornmentDefault; + if (nState & ControlState::FOCUSED) + aListInfo.adornment |= kThemeAdornmentFocus; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height = LISTBOX_HEIGHT; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawButton(&rc, &aListInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + bOK = true; + break; + case ControlPart::ListboxWindow: + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width -= 2 * FOCUS_RING_WIDTH; + rc.size.height -= 2 * FOCUS_RING_WIDTH; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + break; + default: + break; + } + break; + case ControlType::Spinbox: + if (nPart == ControlPart::Entire) + { + + // text field + + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameTextFieldSquare; + aTextDrawInfo.state = getState(nState); + aTextDrawInfo.isFocused = false; + rc.size.width -= SPIN_BUTTON_WIDTH + 4 * FOCUS_RING_WIDTH; + rc.size.height = EDITBOX_HEIGHT; + rc.origin.x += FOCUS_RING_WIDTH; + rc.origin.y += FOCUS_RING_WIDTH; + + // fill a white background, because HIThemeDrawFrame only draws the border + + CGContextFillRect(maContextHolder.get(), CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + if (nState & ControlState::FOCUSED) + HIThemeDrawFocusRect(&rc, true, maContextHolder.get(), kHIThemeOrientationNormal); + + // buttons + + const SpinbuttonValue *pSpinButtonVal = (aValue.getType() == ControlType::SpinButtons) + ? static_cast (&aValue) : nullptr; + ControlState nUpperState = ControlState::ENABLED; + ControlState nLowerState = ControlState::ENABLED; + if (pSpinButtonVal) + { + nUpperState = pSpinButtonVal->mnUpperState; + nLowerState = pSpinButtonVal->mnLowerState; + HIThemeButtonDrawInfo aSpinInfo; + aSpinInfo.kind = kThemeIncDecButton; + aSpinInfo.state = kThemeStateActive; + if (nUpperState & ControlState::PRESSED) + aSpinInfo.state = kThemeStatePressedUp; + else if (nLowerState & ControlState::PRESSED) + aSpinInfo.state = kThemeStatePressedDown; + else if (nUpperState & ~ControlState::ENABLED || nLowerState & ~ControlState::ENABLED) + aSpinInfo.state = kThemeStateInactive; + else if (nUpperState & ControlState::ROLLOVER || nLowerState & ControlState::ROLLOVER) + aSpinInfo.state = kThemeStateRollover; + 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 & ControlState::DEFAULT || nLowerState & ControlState::DEFAULT) + ? kThemeAdornmentDefault : kThemeAdornmentNone; + if (nUpperState & ControlState::FOCUSED || nLowerState & ControlState::FOCUSED) + aSpinInfo.adornment |= kThemeAdornmentFocus; + rc.origin.x += rc.size.width + 2 * FOCUS_RING_WIDTH; + rc.size.width = SPIN_BUTTON_WIDTH; + rc.size.height = SPIN_LOWER_BUTTON_HEIGHT + SPIN_LOWER_BUTTON_HEIGHT; + HIThemeDrawButton(&rc, &aSpinInfo, maContextHolder.get(), kHIThemeOrientationNormal, nullptr); + } + bOK = true; + } + break; + case ControlType::Frame: + { + DrawFrameFlags nStyle = static_cast(aValue.getNumericVal()); + if (nPart == ControlPart::Border) + { + if (!(nStyle & DrawFrameFlags::Menu) && !(nStyle & DrawFrameFlags::WindowBorder)) + { + + // 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 (see issue 84756) + + if (rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight - 3) + { + CGMutablePathRef rPath = CGPathCreateMutable(); + CGPathAddRect(rPath, nullptr, + CGRectMake(0, 0, mpFrame->maGeometry.nWidth - 1, mpFrame->maGeometry.nHeight - 1)); + CGContextBeginPath(maContextHolder.get()); + CGContextAddPath(maContextHolder.get(), rPath); + CGContextClip(maContextHolder.get()); + CGPathRelease(rPath); + } + HIThemeFrameDrawInfo aTextDrawInfo; + aTextDrawInfo.version = 0; + aTextDrawInfo.kind = kHIThemeFrameListBox; + aTextDrawInfo.state = kThemeStateActive; + aTextDrawInfo.isFocused = false; + HIThemeDrawFrame(&rc, &aTextDrawInfo, maContextHolder.get(), kHIThemeOrientationNormal); + bOK = true; + } + } + } + break; + case ControlType::ListNet: + + // do nothing as there isn't net for listviews on macOS + + bOK = true; + break; + default: + break; + } + maContextHolder.restoreState(); + + // 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. Background is always drawn as a whole since we don't know anything about its possible + // contents (see issue i90291). + + if (nType == ControlType::WindowBackground) + { + CGRect aRect = {{0, 0}, {0, 0}}; + if (mxClipPath) + aRect = CGPathGetBoundingBox(mxClipPath); + if (aRect.size.width != 0 && aRect.size.height != 0) + buttonRect.Intersection(tools::Rectangle(Point(static_cast(aRect.origin.x), + static_cast(aRect.origin.y)), + Size(static_cast(aRect.size.width), + static_cast(aRect.size.height)))); + } + RefreshRect(buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight()); + return bOK; +} + +bool AquaSalGraphics::getNativeControlRegion(ControlType nType, + ControlPart nPart, + const tools::Rectangle &rControlRegion, + ControlState, + const ImplControlValue &aValue, + const OUString &, + tools::Rectangle &rNativeBoundingRegion, + tools::Rectangle &rNativeContentRegion) +{ + bool toReturn = false; + tools::Rectangle aCtrlBoundRect(rControlRegion); + short x = aCtrlBoundRect.Left(); + short y = aCtrlBoundRect.Top(); + short w, h; + switch (nType) + { + case ControlType::Pushbutton: + case ControlType::Radiobutton: + case ControlType::Checkbox: + { + if (nType == ControlType::Pushbutton) + { + w = aCtrlBoundRect.GetWidth(); + h = aCtrlBoundRect.GetHeight(); + } + else + { + w = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH + RADIO_BUTTON_TEXT_SEPARATOR; + h = RADIO_BUTTON_SMALL_SIZE + 2 * FOCUS_RING_WIDTH; + } + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Progress: + { + tools::Rectangle aRect(aCtrlBoundRect); + if (aRect.GetHeight() < LARGE_PROGRESS_INDICATOR_HEIGHT) + aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1); + else + aRect.SetBottom(aRect.Top() + LARGE_PROGRESS_INDICATOR_HEIGHT - 1); + rNativeBoundingRegion = aRect; + rNativeContentRegion = aRect; + toReturn = true; + } + break; + case ControlType::IntroProgress: + { + tools::Rectangle aRect(aCtrlBoundRect); + aRect.SetBottom(aRect.Top() + MEDIUM_PROGRESS_INDICATOR_HEIGHT - 1); + rNativeBoundingRegion = aRect; + rNativeContentRegion = aRect; + toReturn = true; + } + break; + case ControlType::Slider: + if (nPart == ControlPart::ThumbHorz) + { + w = SLIDER_WIDTH; + h = aCtrlBoundRect.GetHeight(); + rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ThumbVert) + { + w = aCtrlBoundRect.GetWidth(); + h = SLIDER_HEIGHT; + rNativeBoundingRegion = rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Scrollbar: + { + tools::Rectangle aRect; + if (AquaGetScrollRect(nPart, aCtrlBoundRect, aRect)) + { + toReturn = true; + rNativeBoundingRegion = aRect; + rNativeContentRegion = aRect; + } + } + break; + case ControlType::TabItem: + { + w = aCtrlBoundRect.GetWidth() + 2 * TAB_TEXT_MARGIN - 2 * VCL_TAB_TEXT_SEPARATOR; + h = TAB_HEIGHT + 2; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Editbox: + { + w = aCtrlBoundRect.GetWidth(); + h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + w -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + h -= 2 * (FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Combobox: + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = COMBOBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH; + h = COMBOBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - w; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - COMBOBOX_BUTTON_WIDTH - COMBOBOX_BORDER_WIDTH + - 2 * COMBOBOX_TEXT_MARGIN; + h = COMBOBOX_HEIGHT - 2 * COMBOBOX_BORDER_WIDTH; + x += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH + COMBOBOX_TEXT_MARGIN; + y += FOCUS_RING_WIDTH + COMBOBOX_BORDER_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Listbox: + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = LISTBOX_BUTTON_WIDTH + FOCUS_RING_WIDTH; + h = LISTBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - w; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 2 * FOCUS_RING_WIDTH - LISTBOX_BUTTON_WIDTH - LISTBOX_BORDER_WIDTH + - 2 * LISTBOX_TEXT_MARGIN; + h = LISTBOX_HEIGHT - 2 * LISTBOX_BORDER_WIDTH; + x += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH + LISTBOX_TEXT_MARGIN; + y += FOCUS_RING_WIDTH + LISTBOX_BORDER_WIDTH; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Spinbox: + if (nPart == ControlPart::Entire) + { + w = aCtrlBoundRect.GetWidth(); + h = EDITBOX_HEIGHT + 2 * FOCUS_RING_WIDTH; + x += SPINBOX_OFFSET; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::SubEdit) + { + w = aCtrlBoundRect.GetWidth() - 4 * FOCUS_RING_WIDTH - SPIN_BUTTON_WIDTH - 2 * EDITBOX_BORDER_WIDTH + - 2 * EDITBOX_INSET_MARGIN; + h = EDITBOX_HEIGHT - 2 * (EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN); + x += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN + SPINBOX_OFFSET; + y += FOCUS_RING_WIDTH + EDITBOX_BORDER_WIDTH + EDITBOX_INSET_MARGIN; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonUp) + { + w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH; + h = SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + else if (nPart == ControlPart::ButtonDown) + { + w = SPIN_BUTTON_WIDTH + 2 * FOCUS_RING_WIDTH; + h = SPIN_LOWER_BUTTON_HEIGHT + FOCUS_RING_WIDTH; + x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - 2 * FOCUS_RING_WIDTH + SPINBOX_OFFSET; + y += FOCUS_RING_WIDTH + SPIN_UPPER_BUTTON_HEIGHT; + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + case ControlType::Frame: + { + DrawFrameStyle nStyle = static_cast(aValue.getNumericVal() & 0x000f); + DrawFrameFlags nFlags = static_cast(aValue.getNumericVal() & 0xfff0); + if (nPart == ControlPart::Border + && !(nFlags & (DrawFrameFlags::Menu | DrawFrameFlags::WindowBorder | DrawFrameFlags::BorderWindowBorder))) + { + tools::Rectangle aRect(aCtrlBoundRect); + if (nStyle == DrawFrameStyle::DoubleIn) + { + aRect.AdjustLeft(1); + aRect.AdjustTop(1); + // rRect.Right() -= 1; + // rRect.Bottom() -= 1; + } + else + { + aRect.AdjustLeft(1); + aRect.AdjustTop(1); + aRect.AdjustRight(-1); + aRect.AdjustBottom(-1); + } + rNativeContentRegion = aRect; + rNativeBoundingRegion = aRect; + toReturn = true; + } + } + break; + case ControlType::Menubar: + case ControlType::MenuPopup: + if (nPart == ControlPart::MenuItemCheckMark || nPart == ControlPart::MenuItemRadioMark) + { + w=10; + h=10; + rNativeContentRegion = tools::Rectangle(Point(x, y), Size(w, h)); + rNativeBoundingRegion = tools::Rectangle(Point(x, y), Size(w, h)); + toReturn = true; + } + break; + default: + break; + } + return toReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salnsmenu.mm b/vcl/osx/salnsmenu.mm new file mode 100644 index 000000000..1dba47f03 --- /dev/null +++ b/vcl/osx/salnsmenu.mm @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +@implementation SalNSMenu +-(id)initWithMenu: (AquaSalMenu*)pMenu +{ + mpMenu = pMenu; + return [super initWithTitle: [NSString string]]; +} + +-(void)menuNeedsUpdate: (NSMenu*)pMenu +{ + SolarMutexGuard aGuard; + + 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 + OSL_FAIL( "unconnected menu" ); + } + else if( mpMenu->mpVCLMenu ) + { + mpMenu->mpVCLMenu->Activate(); + mpMenu->mpVCLMenu->Deactivate(); + + // Hide disabled items + NSArray* elements = [pMenu itemArray]; + NSEnumerator* it = [elements objectEnumerator]; + id element; + while ( ( element = [it nextObject] ) != nil ) + { + NSMenuItem* item = static_cast< NSMenuItem* >( element ); + if( ![item isSeparatorItem] ) + [item setHidden: ![item isEnabled]]; + } + } + } +} + +-(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 +{ + (void)aSender; + SolarMutexGuard aGuard; + + // tdf#49853 Keyboard shortcuts are also handled by the menu bar, but at least some of them + // must still end up in the view. This is necessary to handle common edit actions in docked + // windows (e.g. in toolbar fields). + NSEvent* pEvent = [NSApp currentEvent]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12 + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + if( pEvent && [pEvent type] == NSKeyDown ) + { + unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask)); + NSString* charactersIgnoringModifiers = [pEvent charactersIgnoringModifiers]; + if( nModMask == NSCommandKeyMask && + ( [charactersIgnoringModifiers isEqualToString: @"v"] || + [charactersIgnoringModifiers isEqualToString: @"c"] || + [charactersIgnoringModifiers isEqualToString: @"x"] || + [charactersIgnoringModifiers isEqualToString: @"a"] || + [charactersIgnoringModifiers isEqualToString: @"z"] ) ) + { + [[[NSApp keyWindow] contentView] keyDown: pEvent]; + return; + } + } +SAL_WNODEPRECATED_DECLARATIONS_POP + + const AquaSalFrame* pFrame = mpMenuItem->mpParentMenu ? mpMenuItem->mpParentMenu->getFrame() : nullptr; + 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(mpMenuItem->mpVCLMenu.get()); + 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 + OSL_FAIL( "menubar item without frame !" ); + } +} +@end + +@implementation OOStatusItemView +-(void)drawRect: (NSRect)aRect +{ + NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; + [pContext saveGraphicsState]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'drawStatusBarBackgroundInRect:withHighlight:' is deprecated: first deprecated in macOS + // 10.14 - Use the standard button instead which handles highlight drawing, making this + // method obsolete" + [SalData::getStatusItem() drawStatusBarBackgroundInRect: aRect withHighlight: NO]; +SAL_WNODEPRECATED_DECLARATIONS_POP + 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 ) + { + const Size aPixSize = rButtons[i].maButton.maImage.GetSizePixel(); + const NSRect aFromRect = { NSZeroPoint, NSMakeSize( aPixSize.Width(), aPixSize.Height()) }; + aImgRect.origin.y = floor((aFrame.size.height - aFromRect.size.height)/2); + aImgRect.size = aFromRect.size; + if( rButtons[i].mpNSImage ) +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSCompositeSourceOver' is deprecated: first deprecated in macOS 10.12 + [rButtons[i].mpNSImage drawInRect: aImgRect fromRect: aFromRect operation: NSCompositeSourceOver fraction: 1.0]; +SAL_WNODEPRECATED_DECLARATIONS_POP + 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 ) + { + const Size aPixSize = rButtons[i].maButton.maImage.GetSizePixel(); + const NSRect aFromRect = { NSZeroPoint, NSMakeSize( aPixSize.Width(), aPixSize.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, + static_cast(floor((aSize.height-rButtons[i].maButton.maImage.GetSizePixel().Height())/2)) }, + { static_cast(rButtons[i].maButton.maImage.GetSizePixel().Width()), + static_cast(rButtons[i].maButton.maImage.GetSizePixel().Height()) } }; + if( rButtons[i].mpToolTipString ) + [self addToolTipRect: aImgRect owner: rButtons[i].mpToolTipString userData: nullptr]; + aSize.width += 2 + aImgRect.size.width; + } + } + } + [self setFrameSize: aSize]; +} +@end + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salnstimer.mm b/vcl/osx/salnstimer.mm new file mode 100644 index 000000000..95be18164 --- /dev/null +++ b/vcl/osx/salnstimer.mm @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +@implementation TimerCallbackCaller + +-(void)timerElapsed:(NSTimer*)pNSTimer +{ + (void) pNSTimer; + AquaSalTimer *pTimer = static_cast( ImplGetSVData()->maSchedCtx.mpSalTimer ); + if (pTimer) + pTimer->handleTimerElapsed(); +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salobj.cxx b/vcl/osx/salobj.cxx new file mode 100644 index 000000000..75969d4e6 --- /dev/null +++ b/vcl/osx/salobj.cxx @@ -0,0 +1,442 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +AquaSalObject::AquaSalObject( AquaSalFrame* pFrame, SystemWindowData const * pWindowData ) : + mpFrame( pFrame ), + mnClipX( -1 ), + mnClipY( -1 ), + mnClipWidth( -1 ), + mnClipHeight( -1 ), + mbClip( false ), + mnX( 0 ), + mnY( 0 ), + mnWidth( 20 ), + mnHeight( 20 ) +{ + maSysData.mpNSView = nullptr; + maSysData.mbOpenGL = false; + + NSRect aInitFrame = { NSZeroPoint, { 20, 20 } }; + mpClipView = [[NSClipView alloc] initWithFrame: aInitFrame ]; + if( mpClipView ) + { + [mpFrame->getNSView() addSubview: mpClipView]; + [mpClipView setHidden: YES]; + } + if (pWindowData && pWindowData->bOpenGL) + { + maSysData.mbOpenGL = true; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPixelFormat' is deprecated: first deprecated in macOS 10.14 - Please use + // Metal or MetalKit." + NSOpenGLPixelFormat* pixFormat = nullptr; +SAL_WNODEPRECATED_DECLARATIONS_POP + + if (pWindowData->bLegacy) + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPixelFormatAttribute' is deprecated: first deprecated in macOS 10.14" + NSOpenGLPixelFormatAttribute const aAttributes[] = +SAL_WNODEPRECATED_DECLARATIONS_POP + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPFADoubleBuffer' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAAlphaSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAColorSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFADepthSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAMultisample' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFASampleBuffers' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPixelFormatAttribute' is deprecated: first deprecated in macOS + // 10.14", + // "'NSOpenGLPFASamples' is deprecated: first deprecated in macOS 10.14" + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAMultisample, + NSOpenGLPFASampleBuffers, NSOpenGLPixelFormatAttribute(1), + NSOpenGLPFASamples, NSOpenGLPixelFormatAttribute(4), +SAL_WNODEPRECATED_DECLARATIONS_POP + 0 + }; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPixelFormat' is deprecated: first deprecated in macOS 10.14 - Please + // use Metal or MetalKit." + pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:aAttributes]; +SAL_WNODEPRECATED_DECLARATIONS_POP + } + else + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPixelFormatAttribute' is deprecated: first deprecated in macOS 10.14" + NSOpenGLPixelFormatAttribute const aAttributes[] = +SAL_WNODEPRECATED_DECLARATIONS_POP + { +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPFAOpenGLProfile' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLProfileVersion3_2Core' is deprecated: first deprecated in macOS + // 10.14", + // "'NSOpenGLPFADoubleBuffer' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAAlphaSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAColorSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFADepthSize' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFAMultisample' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPFASampleBuffers' is deprecated: first deprecated in macOS 10.14", + // "'NSOpenGLPixelFormatAttribute' is deprecated: first deprecated in macOS + // 10.14", + // "'NSOpenGLPFASamples' is deprecated: first deprecated in macOS 10.14" + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAMultisample, + NSOpenGLPFASampleBuffers, NSOpenGLPixelFormatAttribute(1), + NSOpenGLPFASamples, NSOpenGLPixelFormatAttribute(4), +SAL_WNODEPRECATED_DECLARATIONS_POP + 0 + }; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLPixelFormat' is deprecated: first deprecated in macOS 10.14 - Please + // use Metal or MetalKit." + pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:aAttributes]; +SAL_WNODEPRECATED_DECLARATIONS_POP + } + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + maSysData.mpNSView = [[NSOpenGLView alloc] initWithFrame: aInitFrame pixelFormat:pixFormat]; +SAL_WNODEPRECATED_DECLARATIONS_POP + } + else + { + maSysData.mpNSView = [[NSView alloc] initWithFrame: aInitFrame]; + } + + if( maSysData.mpNSView ) + { + if( mpClipView ) + [mpClipView setDocumentView: maSysData.mpNSView]; + } +} + +AquaSalObject::~AquaSalObject() +{ + assert( GetSalData()->mpInstance->IsMainThread() ); + + if( maSysData.mpNSView ) + { + NSView *pView = maSysData.mpNSView; + [pView removeFromSuperview]; + [pView release]; + } + if( mpClipView ) + { + [mpClipView removeFromSuperview]; + [mpClipView release]; + } +} + +// Please note that the talk about QTMovieView below presumably refers +// to stuff in the QuickTime avmedia thingie, and that QuickTime is +// deprecated, not available for 64-bit code, and won't thus be used +// in a "modern" build of LO anyway. So the relevance of the comment +// is unclear. + +/* + 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(); +} + +void AquaSalObject::BeginSetClipRegion( sal_uInt32 ) +{ + 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() +{ + OSX_SALDATA_RUNINMAIN( setClippedPosSize() ) + + NSRect aViewRect = { NSZeroPoint, NSMakeSize( mnWidth, mnHeight) }; + if( maSysData.mpNSView ) + { + NSView* pNSView = maSysData.mpNSView; + [pNSView setFrame: aViewRect]; + } + + NSRect aClipViewRect = NSMakeRect( mnX, mnY, mnWidth, mnHeight); + NSPoint aClipPt = NSZeroPoint; + 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 ) + return; + + OSX_SALDATA_RUNINMAIN( Show( bVisible ) ) + + [mpClipView setHidden: (bVisible ? NO : YES)]; +} + +const SystemEnvData* AquaSalObject::GetSystemData() const +{ + return &maSysData; +} + +namespace { + +class AquaOpenGLContext : public OpenGLContext +{ +public: + virtual void initWindow() override; + +private: + GLWindow m_aGLWin; + + virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; } + virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; } +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + NSOpenGLView* getOpenGLView(); +SAL_WNODEPRECATED_DECLARATIONS_POP + virtual bool ImplInit() override; + virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override; + virtual void makeCurrent() override; + virtual void destroyCurrentContext() override; + virtual void resetCurrent() override; + virtual void swapBuffers() override; +}; + +} + +void AquaOpenGLContext::resetCurrent() +{ + OSX_SALDATA_RUNINMAIN( resetCurrent() ) + + clearCurrent(); + + OpenGLZone aZone; + + (void) this; // loplugin:staticmethods +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLContext' is deprecated: first deprecated in macOS 10.14 - Please use Metal or + // MetalKit." + [NSOpenGLContext clearCurrentContext]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +void AquaOpenGLContext::makeCurrent() +{ + OSX_SALDATA_RUNINMAIN( makeCurrent() ) + + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + NSOpenGLView* pView = getOpenGLView(); +SAL_WNODEPRECATED_DECLARATIONS_POP + [[pView openGLContext] makeCurrentContext]; + + registerAsCurrent(); +} + +void AquaOpenGLContext::swapBuffers() +{ + OSX_SALDATA_RUNINMAIN( swapBuffers() ) + + OpenGLZone aZone; + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + NSOpenGLView* pView = getOpenGLView(); +SAL_WNODEPRECATED_DECLARATIONS_POP + [[pView openGLContext] flushBuffer]; + + BuffersSwapped(); +} + +SystemWindowData AquaOpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool bRequestLegacyContext) +{ + SystemWindowData aWinData; + aWinData.bOpenGL = true; + aWinData.bLegacy = bRequestLegacyContext; + return aWinData; +} + +void AquaOpenGLContext::destroyCurrentContext() +{ + OSX_SALDATA_RUNINMAIN( destroyCurrentContext() ) +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLContext' is deprecated: first deprecated in macOS 10.14 - Please use Metal or + // MetalKit." + [NSOpenGLContext clearCurrentContext]; +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +void AquaOpenGLContext::initWindow() +{ + OSX_SALDATA_RUNINMAIN( initWindow() ) + + if( !m_pChildWindow ) + { + SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); + m_pChildWindow = VclPtr::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + } +} + +bool AquaOpenGLContext::ImplInit() +{ + OSX_SALDATA_RUNINMAIN_UNION( ImplInit(), boolean ) + + OpenGLZone aZone; + + VCL_GL_INFO("OpenGLContext::ImplInit----start"); +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + NSOpenGLView* pView = getOpenGLView(); +SAL_WNODEPRECATED_DECLARATIONS_POP + [[pView openGLContext] makeCurrentContext]; + + bool bRet = InitGL(); + InitGLDebugging(); + return bRet; +} + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." +NSOpenGLView* AquaOpenGLContext::getOpenGLView() +SAL_WNODEPRECATED_DECLARATIONS_POP +{ +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // "'NSOpenGLView' is deprecated: first deprecated in macOS 10.14 - Please use MTKView + // instead." + return reinterpret_cast(m_pChildWindow->GetSystemData()->mpNSView); +SAL_WNODEPRECATED_DECLARATIONS_POP +} + +OpenGLContext* AquaSalInstance::CreateOpenGLContext() +{ + OSX_SALDATA_RUNINMAIN_POINTER( CreateOpenGLContext(), OpenGLContext* ) + return new AquaOpenGLContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salprn.cxx b/vcl/osx/salprn.cxx new file mode 100644 index 000000000..56510b977 --- /dev/null +++ b/vcl/osx/salprn.cxx @@ -0,0 +1,683 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +using namespace vcl; +using namespace com::sun::star; +using namespace com::sun::star::beans; + +AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) : + mpGraphics( nullptr ), + 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] == NSPaperOrientationLandscape) ? Orientation::Landscape : Orientation::Portrait; + [mpPrintInfo setOrientation: NSPaperOrientationPortrait]; + } + + mpGraphics = new AquaSalGraphics(); + + const int nWidth = 100, nHeight = 100; + mpContextMemory.reset(new (std::nothrow) sal_uInt8[nWidth * 4 * nHeight]); + + if (mpContextMemory) + { + mrContext = CGBitmapContextCreate(mpContextMemory.get(), + nWidth, nHeight, 8, nWidth * 4, + GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst); + if( mrContext ) + SetupPrinterGraphics( mrContext ); + } +} + +AquaSalInfoPrinter::~AquaSalInfoPrinter() +{ + delete mpGraphics; + if( mpPrintInfo ) + [mpPrintInfo release]; + 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 ); + } + else + OSL_FAIL( "no print info in SetupPrinterGraphics" ); + } +} + +SalGraphics* AquaSalInfoPrinter::AcquireGraphics() +{ + SalGraphics* pGraphics = mbGraphics ? nullptr : mpGraphics; + mbGraphics = true; + return pGraphics; +} + +void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics* ) +{ + mbGraphics = false; +} + +bool AquaSalInfoPrinter::Setup( weld::Window*, ImplJobSetup* ) +{ + return false; +} + +bool AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData ) +{ + // FIXME: implement driver data + if( io_pSetupData && io_pSetupData->GetDriverData() ) + return SetData( JobSetFlags::ALL, io_pSetupData ); + + bool bSuccess = true; + + // set system type + io_pSetupData->SetSystem( JOBSETUP_SYSTEM_MAC ); + + // get paper format + if( mpPrintInfo ) + { + NSSize aPaperSize = [mpPrintInfo paperSize]; + double width = aPaperSize.width, height = aPaperSize.height; + // set paper + PaperInfo aInfo( PtTo10Mu( width ), PtTo10Mu( height ) ); + aInfo.doSloppyFit(); + io_pSetupData->SetPaperFormat( aInfo.getPaper() ); + if( io_pSetupData->GetPaperFormat() == PAPER_USER ) + { + io_pSetupData->SetPaperWidth( PtTo10Mu( width ) ); + io_pSetupData->SetPaperHeight( PtTo10Mu( height ) ); + } + else + { + io_pSetupData->SetPaperWidth( 0 ); + io_pSetupData->SetPaperHeight( 0 ); + } + + // set orientation + io_pSetupData->SetOrientation( mePageOrientation ); + + io_pSetupData->SetPaperBin( 0 ); + io_pSetupData->SetDriverData( static_cast(std::malloc( 4 )) ); + io_pSetupData->SetDriverDataLen( 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( OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease]; + [mpPrintInfo setPaperName: pPaperName]; + } + else if( i_nWidth > 0 && i_nHeight > 0 ) + { + NSSize aPaperSize = { static_cast(TenMuToPt(i_nWidth)), static_cast(TenMuToPt(i_nHeight)) }; + [mpPrintInfo setPaperSize: aPaperSize]; + } + // this seems counterintuitive + mePageOrientation = i_eSetOrientation; +} + +bool AquaSalInfoPrinter::SetData( JobSetFlags i_nFlags, ImplJobSetup* io_pSetupData ) +{ + if( ! io_pSetupData || io_pSetupData->GetSystem() != JOBSETUP_SYSTEM_MAC ) + return false; + + if( mpPrintInfo ) + { + if( i_nFlags & JobSetFlags::ORIENTATION ) + mePageOrientation = io_pSetupData->GetOrientation(); + + if( i_nFlags & JobSetFlags::PAPERSIZE ) + { + // set paper format + long width = 21000, height = 29700; + if( io_pSetupData->GetPaperFormat() == PAPER_USER ) + { + // #i101108# sanity check + if( io_pSetupData->GetPaperWidth() && io_pSetupData->GetPaperHeight() ) + { + width = io_pSetupData->GetPaperWidth(); + height = io_pSetupData->GetPaperHeight(); + } + } + else + { + PaperInfo aInfo( io_pSetupData->GetPaperFormat() ); + width = aInfo.getWidth(); + height = aInfo.getHeight(); + } + + setPaperSize( width, height, mePageOrientation ); + } + } + + return mpPrintInfo != nil; +} + +sal_uInt16 AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* ) +{ + return 0; +} + +OUString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup*, sal_uInt16 ) +{ + return OUString(); +} + +sal_uInt32 AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup*, PrinterCapType i_nType ) +{ + switch( i_nType ) + { + case PrinterCapType::SupportDialog: + return 0; + case PrinterCapType::Copies: + return 0xffff; + case PrinterCapType::CollateCopies: + return 0xffff; + case PrinterCapType::SetOrientation: + return 1; + case PrinterCapType::SetPaperSize: + return 1; + case PrinterCapType::SetPaper: + return 1; + case PrinterCapType::ExternalDialog: + return officecfg::Office::Common::Misc::UseSystemPrintDialog::get() + ? 1 : 0; + case PrinterCapType::PDF: + return 1; + case PrinterCapType::UsePullModel: + return 1; + default: break; + } + return 0; +} + +void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*, + long& o_rOutWidth, long& o_rOutHeight, + Point& rPageOffset, + Size& rPaperSize ) +{ + if( mpPrintInfo ) + { + sal_Int32 nDPIX = 72, nDPIY = 72; + mpGraphics->GetResolution( nDPIX, nDPIY ); + const double fXScaling = static_cast(nDPIX)/72.0, + fYScaling = static_cast(nDPIY)/72.0; + + NSSize aPaperSize = [mpPrintInfo paperSize]; + rPaperSize.setWidth( static_cast( double(aPaperSize.width) * fXScaling ) ); + rPaperSize.setHeight( static_cast( double(aPaperSize.height) * fYScaling ) ); + + NSRect aImageRect = [mpPrintInfo imageablePageBounds]; + rPageOffset.setX( static_cast( aImageRect.origin.x * fXScaling ) ); + rPageOffset.setY( static_cast( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling ) ); + o_rOutWidth = static_cast( aImageRect.size.width * fXScaling ); + o_rOutHeight = static_cast( aImageRect.size.height * fYScaling ); + + if( mePageOrientation == Orientation::Landscape ) + { + std::swap( o_rOutWidth, o_rOutHeight ); + // swap width and height + long n = rPaperSize.Width(); + rPaperSize.setWidth(rPaperSize.Height()); + rPaperSize.setHeight(n); + // swap offset x and y + n = rPageOffset.X(); + rPageOffset.setX(rPageOffset.Y()); + rPageOffset.setY(n); + } + } +} + +static Size getPageSize( vcl::PrinterController const & i_rController, sal_Int32 i_nPage ) +{ + Size aPageSize; + uno::Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) ); + for( const PropertyValue & pv : aPageParms ) + { + if ( pv.Name == "PageSize" ) + { + awt::Size aSize; + pv.Value >>= aSize; + aPageSize.setWidth( aSize.Width ); + aPageSize.setHeight( aSize.Height ); + break; + } + } + return aPageSize; +} + +bool AquaSalInfoPrinter::StartJob( const OUString* i_pFileName, + const OUString& i_rJobName, + const OUString& /*i_rAppName*/, + ImplJobSetup* i_pSetupData, + vcl::PrinterController& i_rController + ) +{ + if( mbJob ) + return false; + + bool bSuccess = false; + bool bWasAborted = false; + AquaSalInstance* pInst = GetSalData()->mpInstance; + PrintAccessoryViewState aAccViewState; + sal_Int32 nAllPages = 0; + + // reset IsLastPage + i_rController.setLastPage( false ); + + // update job data + if( i_pSetupData ) + SetData( JobSetFlags::ALL, i_pSetupData ); + + // do we want a progress panel ? + bool bShowProgressPanel = true; + beans::PropertyValue* pMonitor = i_rController.getValue( OUString( "MonitorVisible" ) ); + if( pMonitor ) + pMonitor->Value >>= bShowProgressPanel; + if( ! i_rController.isShowDialogs() ) + bShowProgressPanel = false; + + // possibly create one job for collated output + bool bSinglePrintJobs = false; + beans::PropertyValue* pSingleValue = i_rController.getValue( OUString( "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 + VclPtr pPrinter( i_rController.getPrinter() ); + pPrinter->SetMapMode( MapMode( MapUnit::Map100thMM ) ); + pPrinter->SetPaperSizeUser( aCurSize ); + + // 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:[NSURL fileURLWithPath:pPath] forKey:NSPrintJobSavingURL]; + [pPath release]; + } + + [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies]; + if( nCopies > 1 ) + [pPrintDict setObject: [[NSNumber numberWithBool: pPrinter->IsCollateCopy()] autorelease] forKey: NSPrintMustCollate]; + [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() + && (officecfg::Office::Common::Misc::UseSystemPrintDialog:: + get()) + && 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 accessory view + pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState]; + + bSuccess = true; + mbJob = true; + pInst->startedPrintJob(); + bool wasSuccessful = [pPrintOperation runOperation]; + pInst->endedPrintJob(); + bSuccess = wasSuccessful; + 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 XRenderable::render one last time with IsLastPage = true + i_rController.setLastPage( 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 = [[NSGraphicsContext currentContext] CGContext]; + + SetupPrinterGraphics( rContext ); + + return mpGraphics; +} + +bool AquaSalInfoPrinter::EndPage() +{ + mpGraphics->InvalidateContext(); + return true; +} + +AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) : + mpInfoPrinter( i_pInfoPrinter ) +{ +} + +AquaSalPrinter::~AquaSalPrinter() +{ +} + +bool AquaSalPrinter::StartJob( const OUString* i_pFileName, + const OUString& i_rJobName, + const OUString& 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 OUString* /*i_pFileName*/, + const OUString& /*i_rJobName*/, + const OUString& /*i_rAppName*/, + sal_uInt32 /*i_nCopies*/, + bool /*i_bCollate*/, + bool /*i_bDirect*/, + ImplJobSetup* ) +{ + OSL_FAIL( "should never be called" ); + return false; +} + +bool AquaSalPrinter::EndJob() +{ + return mpInfoPrinter->EndJob(); +} + +SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, bool i_bNewJobData ) +{ + return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData ); +} + +void AquaSalPrinter::EndPage() +{ + mpInfoPrinter->EndPage(); +} + +void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) +{ + m_aPaperFormats.clear(); + m_bPapersInit = true; + + if( mpPrinter ) + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + //TODO: 10.9 statusForTable:, stringListForKey:inTable: + 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]; + // first try to match the name + OString aPaperName( [pPaper UTF8String] ); + Paper ePaper = PaperInfo::fromPSName( aPaperName ); + if( ePaper != PAPER_USER ) + { + m_aPaperFormats.push_back( PaperInfo( ePaper ) ); + } + else + { + NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper]; + if( aPaperSize.width > 0 && aPaperSize.height > 0 ) + { + PaperInfo aInfo( PtTo10Mu( aPaperSize.width ), + PtTo10Mu( aPaperSize.height ) ); + if( aInfo.getPaper() == PAPER_USER ) + aInfo.doSloppyFit(); + m_aPaperFormats.push_back( aInfo ); + } + } + } + } + } + SAL_WNODEPRECATED_DECLARATIONS_POP + } +} + +const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const +{ + if( ! m_bPapersInit ) + const_cast(this)->InitPaperFormats( nullptr ); + + const PaperInfo* pMatch = nullptr; + o_rOrientation = Orientation::Portrait; + for( int n = 0; n < 2 ; n++ ) + { + for( size_t i = 0; i < m_aPaperFormats.size(); i++ ) + { + if( std::abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 && + std::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* ) +{ + return 900; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/salsys.cxx b/vcl/osx/salsys.cxx new file mode 100644 index 000000000..36c92b8f2 --- /dev/null +++ b/vcl/osx/salsys.cxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include +#include + +#include + +AquaSalSystem::~AquaSalSystem() +{ +} + +unsigned int AquaSalSystem::GetDisplayScreenCount() +{ + NSArray* pScreens = [NSScreen screens]; + return pScreens ? [pScreens count] : 1; +} + +tools::Rectangle AquaSalSystem::GetDisplayScreenPosSizePixel( unsigned int nScreen ) +{ + if (Application::IsBitmapRendering()) + { + tools::Rectangle aRect; + if (nScreen == 0) + aRect = tools::Rectangle(Point(0,0), Size(1024, 768)); + return aRect; + } + + NSArray* pScreens = [NSScreen screens]; + tools::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 = tools::Rectangle( Point( static_cast(aFrame.origin.x), static_cast(aFrame.origin.y) ), + Size( static_cast(aFrame.size.width), static_cast(aFrame.size.height) ) ); + } + return aRet; +} + +static NSString* getStandardString( StandardButtonType nButtonId, bool bUseResources ) +{ + OUString aText; + if( bUseResources ) + { + aText = GetStandardText( nButtonId ); + } + if( aText.isEmpty() ) // this is for bad cases, we might be missing the vcl resource + { + switch( nButtonId ) + { + case StandardButtonType::OK: aText = "OK";break; + case StandardButtonType::Abort: aText = "Abort";break; + case StandardButtonType::Cancel: aText = "Cancel";break; + case StandardButtonType::Retry: aText = "Retry";break; + case StandardButtonType::Yes: aText = "Yes";break; + case StandardButtonType::No: aText = "No";break; + default: break; + } + } + return aText.isEmpty() ? nil : CreateNSString( aText); +} + +int AquaSalSystem::ShowNativeMessageBox( const OUString& rTitle, + const OUString& rMessage ) +{ + NSString* pTitle = CreateNSString( rTitle ); + NSString* pMessage = CreateNSString( rMessage ); + + NSString* pDefText = getStandardString( StandardButtonType::OK, false/*bUseResources*/ ); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.10 NSRunAlertPanel + int nResult = NSRunAlertPanel( pTitle, @"%@", pDefText, nil, nil, pMessage ); + SAL_WNODEPRECATED_DECLARATIONS_POP + + if( pTitle ) + [pTitle release]; + if( pMessage ) + [pMessage release]; + if( pDefText ) + [pDefText release]; + + int nRet = 0; + if( nResult == 1 ) + nRet = SALSYSTEM_SHOWNATIVEMSGBOX_BTN_OK; + + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/saltimer.cxx b/vcl/osx/saltimer.cxx new file mode 100644 index 000000000..55593e64e --- /dev/null +++ b/vcl/osx/saltimer.cxx @@ -0,0 +1,209 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + + +void ImplNSAppPostEvent( short nEventId, BOOL bAtStart, int nUserData ) +{ + ReleasePoolHolder aPool; +SAL_WNODEPRECATED_DECLARATIONS_PUSH +// 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 + NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined +SAL_WNODEPRECATED_DECLARATIONS_POP + location: NSZeroPoint + modifierFlags: 0 + timestamp: [[NSProcessInfo processInfo] systemUptime] + windowNumber: 0 + context: nil + subtype: nEventId + data1: nUserData + data2: 0]; + assert( pEvent ); + if ( nil == pEvent ) + return; + if ( NO == bAtStart ) + { + // nextEventMatchingMask has to run in the main thread! + assert([NSThread isMainThread]); + + // Posting an event to the end of an empty queue fails, + // so we peek the queue and post to the start, if empty. + // Some Qt bugs even indicate nextEvent without dequeue + // sometimes blocks, so we dequeue and re-add the event. + NSEvent* pPeekEvent = [NSApp nextEventMatchingMask: NSEventMaskAny + untilDate: nil + inMode: NSDefaultRunLoopMode + dequeue: YES]; + if ( nil == pPeekEvent ) + bAtStart = YES; + else + [NSApp postEvent: pPeekEvent atStart: YES]; + } + [NSApp postEvent: pEvent atStart: bAtStart]; +} + +void AquaSalTimer::queueDispatchTimerEvent( bool bAtStart ) +{ + Stop(); + m_bDirectTimeout = true; + ImplNSAppPostEvent( AquaSalInstance::DispatchTimerEvent, + bAtStart, GetNextEventVersion() ); +} + +void AquaSalTimer::Start( sal_uInt64 nMS ) +{ + SalData* pSalData = GetSalData(); + + if( !pSalData->mpInstance->IsMainThread() ) + { + ImplNSAppPostEvent( AquaSalInstance::AppStartTimerEvent, YES, nMS ); + return; + } + + m_bDirectTimeout = (0 == nMS) && !pSalData->mpInstance->mbIsLiveResize; + if ( m_bDirectTimeout ) + Stop(); + else + { + NSTimeInterval aTI = double(nMS) / 1000.0; + if( m_pRunningTimer != nil ) + { + if ([m_pRunningTimer isValid] && rtl::math::approxEqual( + [m_pRunningTimer timeInterval], aTI)) + { + // set new fire date + [m_pRunningTimer setFireDate: [NSDate dateWithTimeIntervalSinceNow: aTI]]; + } + else + Stop(); + } + else + Stop(); + if( m_pRunningTimer == nil ) + { + m_pRunningTimer = [[NSTimer scheduledTimerWithTimeInterval: aTI + target: [[[TimerCallbackCaller alloc] init] autorelease] + selector: @selector(timerElapsed:) + userInfo: nil + repeats: NO + ] retain]; + /* #i84055# add timer to tracking run loop mode, + so they also elapse while e.g. life resize + */ + [[NSRunLoop currentRunLoop] addTimer: m_pRunningTimer forMode: NSEventTrackingRunLoopMode]; + } + } +} + +void AquaSalTimer::Stop() +{ + assert( GetSalData()->mpInstance->IsMainThread() ); + + if( m_pRunningTimer != nil ) + { + [m_pRunningTimer invalidate]; + [m_pRunningTimer release]; + m_pRunningTimer = nil; + } + InvalidateEvent(); +} + +void AquaSalTimer::callTimerCallback() +{ + ImplSVData* pSVData = ImplGetSVData(); + SolarMutexGuard aGuard; + m_bDirectTimeout = false; + if( pSVData->maSchedCtx.mpSalTimer ) + pSVData->maSchedCtx.mpSalTimer->CallCallback(); +} + +void AquaSalTimer::handleTimerElapsed() +{ + if ( m_bDirectTimeout || GetSalData()->mpInstance->mbIsLiveResize ) + { + // Stop the timer, as it is just invalidated after the firing function + Stop(); + callTimerCallback(); + } + else + queueDispatchTimerEvent( true ); +} + +bool AquaSalTimer::handleDispatchTimerEvent( NSEvent *pEvent ) +{ + bool bIsValidEvent = IsValidEventVersion( [pEvent data1] ); + if ( bIsValidEvent ) + callTimerCallback(); + return bIsValidEvent; +} + +void AquaSalTimer::handleStartTimerEvent( NSEvent* pEvent ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData->maSchedCtx.mpSalTimer ) + { + NSTimeInterval posted = [pEvent timestamp] + NSTimeInterval([pEvent data1])/1000.0; + NSTimeInterval current = [NSDate timeIntervalSinceReferenceDate]; + sal_uLong nTimeoutMS = 0; + if( (posted - current) > 0.0 ) + nTimeoutMS = ceil( (posted - current) * 1000 ); + Start( nTimeoutMS ); + } +} + +bool AquaSalTimer::IsTimerElapsed() const +{ + assert( !((ExistsValidEvent() || m_bDirectTimeout) && m_pRunningTimer) ); + if ( ExistsValidEvent() || m_bDirectTimeout ) + return true; + if ( !m_pRunningTimer ) + return false; + NSDate* pDt = [m_pRunningTimer fireDate]; + return pDt && ([pDt timeIntervalSinceNow] < 0); +} + +AquaSalTimer::AquaSalTimer( ) + : m_pRunningTimer( nil ) +{ +} + +AquaSalTimer::~AquaSalTimer() +{ + Stop(); +} + +void AquaSalTimer::handleWindowShouldClose() +{ + // for whatever reason events get filtered on close, presumably by + // timestamp so post a new timeout event, if there was one queued... + if ( ExistsValidEvent() && !m_pRunningTimer ) + queueDispatchTimerEvent( false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/service_entry.cxx b/vcl/osx/service_entry.cxx new file mode 100644 index 000000000..eebb675ce --- /dev/null +++ b/vcl/osx/service_entry.cxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +#include +#include + +#include "DragSource.hxx" +#include "DropTarget.hxx" +#include "clipboard.hxx" + +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::cppu; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; + +uno::Reference< XInterface > AquaSalInstance::CreateClipboard( const Sequence< Any >& i_rArguments ) +{ + if ( Application::IsHeadlessModeEnabled() ) + return SalInstance::CreateClipboard( i_rArguments ); + + SalData* pSalData = GetSalData(); + if( ! pSalData->mxClipboard.is() ) + pSalData->mxClipboard.set(static_cast< XClipboard* >(new AquaClipboard(nullptr, true)), UNO_QUERY); + return pSalData->mxClipboard; +} + +uno::Reference AquaSalInstance::CreateDragSource() +{ + if ( Application::IsHeadlessModeEnabled() ) + return SalInstance::CreateDragSource(); + + return uno::Reference(static_cast< XInitialization* >(new DragSource()), UNO_QUERY); +} + +uno::Reference AquaSalInstance::CreateDropTarget() +{ + if ( Application::IsHeadlessModeEnabled() ) + return SalInstance::CreateDropTarget(); + + return uno::Reference(static_cast< XInitialization* >(new DropTarget()), UNO_QUERY); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm new file mode 100644 index 000000000..53d002a8a --- /dev/null +++ b/vcl/osx/vclnsapp.mm @@ -0,0 +1,473 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#import "Carbon/Carbon.h" +#import "apple_remote/RemoteControl.h" +#include + + +@implementation CocoaThreadEnabler +-(void)enableCocoaThreads:(id)param +{ + // do nothing, this is just to start an NSThread and therefore put + // Cocoa into multithread mode + (void)param; +} +@end + +// If you wonder how this VCL_NSApplication stuff works, one thing you +// might have missed is that the NSPrincipalClass property in +// desktop/macosx/Info.plist has the value VCL_NSApplication. + +@implementation VCL_NSApplication + +-(void)applicationDidFinishLaunching:(NSNotification*)pNotification +{ + (void)pNotification; + +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 + NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined + location: NSZeroPoint + modifierFlags: 0 + timestamp: [[NSProcessInfo processInfo] systemUptime] + windowNumber: 0 + context: nil + subtype: AquaSalInstance::AppExecuteSVMain + data1: 0 + data2: 0 ]; +SAL_WNODEPRECATED_DECLARATIONS_POP + assert( pEvent ); + [NSApp postEvent: pEvent atStart: NO]; + + if( [NSWindow respondsToSelector:@selector(allowsAutomaticWindowTabbing)] ) + { + [NSWindow setAllowsAutomaticWindowTabbing:NO]; + } +} + +-(void)sendEvent:(NSEvent*)pEvent +{ + NSEventType eType = [pEvent type]; +SAL_WNODEPRECATED_DECLARATIONS_PUSH + // 'NSAlternateKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12 + // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSCommandKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSControlKeyMask' is deprecated: first deprecated in macOS 10.12 + // 'NSKeyDown' is deprecated: first deprecated in macOS 10.12 + // 'NSMiniaturizableWindowMask' is deprecated: first deprecated in macOS 10.12 + // 'NSShiftKeyMask' is deprecated: first deprecated in macOS 10.12 + if( eType == NSApplicationDefined ) + { + AquaSalInstance::handleAppDefinedEvent( pEvent ); + } + else if( eType == NSKeyDown && ([pEvent modifierFlags] & NSCommandKeyMask) != 0 ) + { + NSWindow* pKeyWin = [NSApp keyWindow]; + if( pKeyWin && [pKeyWin isKindOfClass: [SalFrameWindow class]] ) + { + AquaSalFrame* pFrame = [static_cast(pKeyWin) getSalFrame]; + unsigned int nModMask = ([pEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSAlternateKeyMask|NSCommandKeyMask)); + /* + * #i98949# - Cmd-M miniaturize window, Cmd-Option-M miniaturize all windows + */ + if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"m"] ) + { + if ( nModMask == NSCommandKeyMask && ([pFrame->getNSWindow() styleMask] & NSMiniaturizableWindowMask) ) + { + [pFrame->getNSWindow() performMiniaturize: nil]; + return; + } + + if ( nModMask == ( NSCommandKeyMask | NSAlternateKeyMask ) ) + { + [NSApp miniaturizeAll: nil]; + 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 & SalFrameStyleFlags::FLOAT) ) + { + [[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 == nullptr || ! [NSMenu menuBarVisible] || ! [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( [[pEvent charactersIgnoringModifiers] isEqualToString: @"a"] ) + { + if( [NSApp sendAction: @selector(selectAll:) to: nil from: nil] ) + return; + } + else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"z"] ) + { + if( [NSApp sendAction: @selector(undo:) to: nil from: nil] ) + return; + } + } + else if( nModMask == (NSCommandKeyMask|NSShiftKeyMask) ) + { + if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"Z"] ) + { + if( [NSApp sendAction: @selector(redo:) to: nil from: nil] ) + return; + } + } + } + } +SAL_WNODEPRECATED_DECLARATIONS_POP + [super sendEvent: pEvent]; +} + +-(void)sendSuperEvent:(NSEvent*)pEvent +{ + [super sendEvent: pEvent]; +} + +-(NSMenu*)applicationDockMenu:(NSApplication *)sender +{ + (void)sender; + return AquaSalInstance::GetDynamicDockMenu(); +} + +-(BOOL)application: (NSApplication*)app openFile: (NSString*)pFile +{ + (void)app; + std::vector aFile; + aFile.push_back( GetOUString( pFile ) ); + if( ! AquaSalInstance::isOnCommandLine( aFile[0] ) ) + { + const ApplicationEvent* pAppEvent = new ApplicationEvent(ApplicationEvent::Type::Open, aFile); + AquaSalInstance::aAppEventList.push_back( pAppEvent ); + AquaSalInstance *pInst = GetSalData()->mpInstance; + if( pInst ) + pInst->TriggerUserEventProcessing(); + } + return YES; +} + +-(void)application: (NSApplication*) app openFiles: (NSArray*)files +{ + (void)app; + std::vector aFileList; + + NSEnumerator* it = [files objectEnumerator]; + NSString* pFile = nil; + + while( (pFile = [it nextObject]) != nil ) + { + const OUString aFile( GetOUString( pFile ) ); + if( ! AquaSalInstance::isOnCommandLine( aFile ) ) + { + aFileList.push_back( aFile ); + } + } + + if( !aFileList.empty() ) + { + // 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(ApplicationEvent::Type::Open, aFileList); + AquaSalInstance::aAppEventList.push_back( pAppEvent ); + AquaSalInstance *pInst = GetSalData()->mpInstance; + if( pInst ) + pInst->TriggerUserEventProcessing(); + } +} + +-(BOOL)application: (NSApplication*)app printFile: (NSString*)pFile +{ + (void)app; + std::vector aFile; + aFile.push_back( GetOUString( pFile ) ); + const ApplicationEvent* pAppEvent = new ApplicationEvent(ApplicationEvent::Type::Print, aFile); + AquaSalInstance::aAppEventList.push_back( pAppEvent ); + AquaSalInstance *pInst = GetSalData()->mpInstance; + if( pInst ) + pInst->TriggerUserEventProcessing(); + return YES; +} +-(NSApplicationPrintReply)application: (NSApplication *) app printFiles:(NSArray *)files withSettings: (NSDictionary *)printSettings showPrintPanels:(BOOL)bShowPrintPanels +{ + (void)app; + (void)printSettings; + (void)bShowPrintPanels; + // currently ignores print settings a bShowPrintPanels + std::vector aFileList; + + NSEnumerator* it = [files objectEnumerator]; + NSString* pFile = nil; + + while( (pFile = [it nextObject]) != nil ) + { + aFileList.push_back( GetOUString( pFile ) ); + } + const ApplicationEvent* pAppEvent = new ApplicationEvent(ApplicationEvent::Type::Print, aFileList); + AquaSalInstance::aAppEventList.push_back( pAppEvent ); + AquaSalInstance *pInst = GetSalData()->mpInstance; + if( pInst ) + pInst->TriggerUserEventProcessing(); + // we have no back channel here, we have to assume success + // correct handling would be NSPrintingReplyLater and then send [app replyToOpenOrPrint] + return NSPrintingSuccess; +} + +-(void)applicationWillTerminate: (NSNotification *) aNotification +{ + (void)aNotification; + sal_detail_deinitialize(); + _Exit(0); +} + +-(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app +{ + (void)app; + NSApplicationTerminateReply aReply = NSTerminateNow; + { + SolarMutexGuard aGuard; + + AquaSalInstance *pInst = GetSalData()->mpInstance; + SalFrame *pAnyFrame = pInst->anyFrame(); + if( pAnyFrame ) + { + // the following QueryExit will likely present a message box, activate application + [NSApp activateIgnoringOtherApps: YES]; + aReply = pAnyFrame->CallCallback( SalEvent::Shutdown, nullptr ) ? NSTerminateCancel : NSTerminateNow; + } + + if( aReply == NSTerminateNow ) + { + ApplicationEvent aEv(ApplicationEvent::Type::PrivateDoShutdown); + GetpApp()->AppEvent( aEv ); + ImageTree::get().shutdown(); + // DeInitVCL should be called in ImplSVMain - unless someone exits first which + // can occur in Desktop::doShutdown for example + } + } + + return aReply; +} + +-(void)systemColorsChanged: (NSNotification*) pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + AquaSalInstance *pInst = GetSalData()->mpInstance; + SalFrame *pAnyFrame = pInst->anyFrame(); + if( pAnyFrame ) + pAnyFrame->CallCallback( SalEvent::SettingsChanged, nullptr ); +} + +-(void)screenParametersChanged: (NSNotification*) pNotification +{ + (void)pNotification; + SolarMutexGuard aGuard; + + for( auto pSalFrame : GetSalData()->mpInstance->getFrames() ) + { + AquaSalFrame *pFrame = static_cast( pSalFrame ); + pFrame->screenParametersChanged(); + } +} + +-(void)scrollbarVariantChanged: (NSNotification*) pNotification +{ + (void)pNotification; + GetSalData()->mpInstance->delayedSettingsChanged( true ); +} + +-(void)scrollbarSettingsChanged: (NSNotification*) pNotification +{ + (void)pNotification; + GetSalData()->mpInstance->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 + +#if !HAVE_FEATURE_MACOSX_SANDBOX +- (void)applicationWillBecomeActive:(NSNotification *)pNotification +{ + (void)pNotification; + SalData* pSalData = GetSalData(); + AppleRemoteMainController* pAppleRemoteCtrl = pSalData->mpAppleRemoteMainController; + if( pAppleRemoteCtrl && pAppleRemoteCtrl->remoteControl) + { + // [remoteControl startListening: self]; + // does crash because the right thing to do is + // [pAppleRemoteCtrl->remoteControl startListening: self]; + // but the instance variable 'remoteControl' is declared protected + // workaround : declare remoteControl instance variable as public in RemoteMainController.m + + [pAppleRemoteCtrl->remoteControl startListening: self]; +#ifdef DEBUG + NSLog(@"Apple Remote will become active - Using remote controls"); +#endif + } + for( std::list< AquaSalFrame* >::const_iterator it = pSalData->maPresentationFrames.begin(); + it != pSalData->maPresentationFrames.end(); ++it ) + { + NSWindow* pNSWindow = (*it)->getNSWindow(); + [pNSWindow setLevel: NSPopUpMenuWindowLevel]; + if( [pNSWindow isVisible] ) + [pNSWindow orderFront: NSApp]; + } +} + +- (void)applicationWillResignActive:(NSNotification *)pNotification +{ + (void)pNotification; + SalData* pSalData = GetSalData(); + AppleRemoteMainController* pAppleRemoteCtrl = pSalData->mpAppleRemoteMainController; + if( pAppleRemoteCtrl && pAppleRemoteCtrl->remoteControl) + { + // [remoteControl stopListening: self]; + // does crash because the right thing to do is + // [pAppleRemoteCtrl->remoteControl stopListening: self]; + // but the instance variable 'remoteControl' is declared protected + // workaround : declare remoteControl instance variable as public in RemoteMainController.m + + [pAppleRemoteCtrl->remoteControl stopListening: self]; +#ifdef DEBUG + NSLog(@"Apple Remote will resign active - Releasing remote controls"); +#endif + } + for( std::list< AquaSalFrame* >::const_iterator it = pSalData->maPresentationFrames.begin(); + it != pSalData->maPresentationFrames.end(); ++it ) + { + [(*it)->getNSWindow() setLevel: NSNormalWindowLevel]; + } +} +#endif + +- (BOOL)applicationShouldHandleReopen: (NSApplication*)pApp hasVisibleWindows: (BOOL) bWinVisible +{ + (void)pApp; + (void)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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/afl-eventtesting/README.eventtesting b/vcl/qa/afl-eventtesting/README.eventtesting new file mode 100644 index 000000000..963bed1cd --- /dev/null +++ b/vcl/qa/afl-eventtesting/README.eventtesting @@ -0,0 +1,24 @@ +Notes on experimental afl driven ui fuzzing + +only keyboard events for now + +vcl/workben/eventtesting.writer is just serialized "hello" + ctrl+a + ctrl+b +keystrokes to get things started + +vcl/workben/eventtesting.impress is a bit more involved and inserts text, +a new slide via the menu, bullets and undos for all of that + +currently an arbitrary limit of 50 keystrokes before application quits in +order to initially explore that shallow space + +writer: +Xnest :1 +cp vcl/workben/eventtesting.writer eventtesting +afl-fuzz -f eventtesting -t 10000 -i ~/fuzz/in.vcl -o ~/fuzz/out.vcl -d -T vcl -m 50000000 instdir/program/soffice.bin --nologo --writer --eventtesting --norestore --display :1 + +impress: +Xnest :1 +cp vcl/workben/eventtesting.impress eventtesting +afl-fuzz -f eventtesting -t 10000 -i ~/fuzz/in.vcl -o ~/fuzz/out.vcl -d -T vcl -m 50000000 instdir/program/soffice.bin --nologo --impress --eventtesting --norestore --display :1 + +This also works with --headless and no --display entry and thus no Xnest required diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress b/vcl/qa/afl-eventtesting/eventtesting.impress new file mode 100644 index 000000000..ac7991875 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress.crash-1 b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-1 new file mode 100644 index 000000000..f8802b5ad Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-1 differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress.crash-2 b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-2 new file mode 100644 index 000000000..d312939e4 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-2 differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress.crash-3 b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-3 new file mode 100644 index 000000000..e6639bab1 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-3 differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress.crash-4 b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-4 new file mode 100644 index 000000000..3b0f9bc82 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-4 differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.impress.crash-5 b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-5 new file mode 100644 index 000000000..022175453 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.impress.crash-5 differ diff --git a/vcl/qa/afl-eventtesting/eventtesting.writer b/vcl/qa/afl-eventtesting/eventtesting.writer new file mode 100644 index 000000000..b85a20356 Binary files /dev/null and b/vcl/qa/afl-eventtesting/eventtesting.writer differ diff --git a/vcl/qa/api/XGraphicTest.cxx b/vcl/qa/api/XGraphicTest.cxx new file mode 100644 index 000000000..accc384d2 --- /dev/null +++ b/vcl/qa/api/XGraphicTest.cxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace +{ +using namespace css; + +static OUString const gaDataUrl = "/vcl/qa/api/data/"; + +class XGraphicTest : public test::BootstrapFixture +{ +public: + XGraphicTest() + : BootstrapFixture(true, false) + { + } + + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + + void testGraphic(); + void testGraphicDescriptor(); + void testGraphicProvider(); + + CPPUNIT_TEST_SUITE(XGraphicTest); + CPPUNIT_TEST(testGraphic); + CPPUNIT_TEST(testGraphicDescriptor); + CPPUNIT_TEST(testGraphicProvider); + CPPUNIT_TEST_SUITE_END(); +}; + +BitmapEx createBitmap() +{ + Bitmap aBitmap(Size(100, 50), 24); + aBitmap.Erase(COL_LIGHTRED); + + return BitmapEx(aBitmap); +} + +void XGraphicTest::testGraphic() +{ + Graphic aGraphic; + uno::Reference xGraphic = aGraphic.GetXGraphic(); +} + +void XGraphicTest::testGraphicDescriptor() +{ + Graphic aGraphic(createBitmap()); + uno::Reference xGraphic = aGraphic.GetXGraphic(); + uno::Reference xGraphicDescriptor(xGraphic, uno::UNO_QUERY_THROW); + + //[property] byte GraphicType; + sal_Int8 nType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("GraphicType") >>= nType); + CPPUNIT_ASSERT_EQUAL(graphic::GraphicType::PIXEL, nType); + + //[property] string MimeType; + OUString sMimeType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("MimeType") >>= sMimeType); + CPPUNIT_ASSERT_EQUAL(OUString("image/x-vclgraphic"), sMimeType); + + //[optional, property] ::com::sun::star::awt::Size SizePixel; + awt::Size aSizePixel; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("SizePixel") >>= aSizePixel); + CPPUNIT_ASSERT_EQUAL(sal_Int32(100), aSizePixel.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(50), aSizePixel.Height); + + //[optional, property] ::com::sun::star::awt::Size Size100thMM; + awt::Size aSize100thMM; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Size100thMM") >>= aSize100thMM); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSize100thMM.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aSize100thMM.Height); + + //[optional, property] byte BitsPerPixel; + sal_Int8 nBitsPerPixel; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("BitsPerPixel") >>= nBitsPerPixel); + CPPUNIT_ASSERT_EQUAL(sal_Int8(24), nBitsPerPixel); + + //[optional, property] boolean Transparent; + bool bTransparent; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Transparent") >>= bTransparent); + CPPUNIT_ASSERT_EQUAL(false, bTransparent); + + //[optional, property] boolean Alpha; + bool bAlpha; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Alpha") >>= bAlpha); + CPPUNIT_ASSERT_EQUAL(false, bAlpha); + + //[optional, property] boolean Animated; + bool bAnimated; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Animated") >>= bAnimated); + CPPUNIT_ASSERT_EQUAL(false, bAnimated); +} + +void XGraphicTest::testGraphicProvider() +{ + OUString aGraphicURL = getFullUrl("TestGraphic.png"); + + { // Load lazy + uno::Reference xContext(comphelper::getProcessComponentContext()); + uno::Reference xGraphicProvider; + xGraphicProvider.set(graphic::GraphicProvider::create(xContext), uno::UNO_SET_THROW); + + auto aMediaProperties(comphelper::InitPropertySequence({ + { "URL", uno::makeAny(aGraphicURL) }, + { "LazyRead", uno::makeAny(true) }, + { "LoadAsLink", uno::makeAny(false) }, + })); + + uno::Reference xGraphic( + xGraphicProvider->queryGraphic(aMediaProperties)); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + uno::Reference xGraphicDescriptor(xGraphic, uno::UNO_QUERY_THROW); + + sal_Int8 nType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("GraphicType") >>= nType); + CPPUNIT_ASSERT_EQUAL(graphic::GraphicType::PIXEL, nType); + + awt::Size aSizePixel; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("SizePixel") >>= aSizePixel); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Height); + + bool bLinked; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Linked") >>= bLinked); + CPPUNIT_ASSERT_EQUAL(false, bLinked); + + OUString sOriginURL; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("OriginURL") >>= sOriginURL); + CPPUNIT_ASSERT_EQUAL(OUString(), sOriginURL); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + } + + { // Load as link + uno::Reference xContext(comphelper::getProcessComponentContext()); + uno::Reference xGraphicProvider; + xGraphicProvider.set(graphic::GraphicProvider::create(xContext), uno::UNO_SET_THROW); + + auto aMediaProperties(comphelper::InitPropertySequence({ + { "URL", uno::makeAny(aGraphicURL) }, + { "LazyRead", uno::makeAny(false) }, + { "LoadAsLink", uno::makeAny(true) }, + })); + + uno::Reference xGraphic( + xGraphicProvider->queryGraphic(aMediaProperties)); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + uno::Reference xGraphicDescriptor(xGraphic, uno::UNO_QUERY_THROW); + + sal_Int8 nType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("GraphicType") >>= nType); + CPPUNIT_ASSERT_EQUAL(graphic::GraphicType::PIXEL, nType); + + awt::Size aSizePixel; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("SizePixel") >>= aSizePixel); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Height); + + bool bLinked; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Linked") >>= bLinked); + CPPUNIT_ASSERT_EQUAL(true, bLinked); + + OUString sOriginURL; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("OriginURL") >>= sOriginURL); + CPPUNIT_ASSERT_EQUAL(aGraphicURL, sOriginURL); + } + + { // Load lazy and as link + uno::Reference xContext(comphelper::getProcessComponentContext()); + uno::Reference xGraphicProvider; + xGraphicProvider.set(graphic::GraphicProvider::create(xContext), uno::UNO_SET_THROW); + + auto aMediaProperties(comphelper::InitPropertySequence({ + { "URL", uno::makeAny(aGraphicURL) }, + { "LazyRead", uno::makeAny(true) }, + { "LoadAsLink", uno::makeAny(true) }, + })); + + uno::Reference xGraphic( + xGraphicProvider->queryGraphic(aMediaProperties)); + CPPUNIT_ASSERT(xGraphic.is()); + Graphic aGraphic(xGraphic); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + uno::Reference xGraphicDescriptor(xGraphic, uno::UNO_QUERY_THROW); + + sal_Int8 nType; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("GraphicType") >>= nType); + CPPUNIT_ASSERT_EQUAL(graphic::GraphicType::PIXEL, nType); + + awt::Size aSizePixel; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("SizePixel") >>= aSizePixel); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Width); + CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aSizePixel.Height); + + bool bLinked; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("Linked") >>= bLinked); + CPPUNIT_ASSERT_EQUAL(true, bLinked); + + OUString sOriginURL; + CPPUNIT_ASSERT(xGraphicDescriptor->getPropertyValue("OriginURL") >>= sOriginURL); + CPPUNIT_ASSERT_EQUAL(aGraphicURL, sOriginURL); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(XGraphicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/api/data/TestGraphic.png b/vcl/qa/api/data/TestGraphic.png new file mode 100644 index 000000000..fe0c3c8ae Binary files /dev/null and b/vcl/qa/api/data/TestGraphic.png differ diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx new file mode 100644 index 000000000..ff4ed0d87 --- /dev/null +++ b/vcl/qa/cppunit/BackendTest.cxx @@ -0,0 +1,599 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +#include +#include +#include +#include + +#include + +class BackendTest : public test::BootstrapFixture +{ + // if enabled - check the result images with: + // "xdg-open ./workdir/CppunitTest/vcl_backend_test.test.core/" + static constexpr const bool mbExportBitmap = false; + + void exportImage(OUString const& rsFilename, BitmapEx const& rBitmapEx) + { + if (mbExportBitmap) + { + BitmapEx aBitmapEx(rBitmapEx); + aBitmapEx.Scale(Size(128, 128), BmpScaleFlag::Fast); + SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); + } + } + + void exportImage(OUString const& rsFilename, Bitmap const& rBitmap) + { + if (mbExportBitmap) + { + Bitmap aBitmap(rBitmap); + aBitmap.Scale(Size(128, 128), BmpScaleFlag::Fast); + SvFileStream aStream(rsFilename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmap, aStream); + } + } + + void exportDevice(const OUString& filename, const VclPtr& device) + { + if (mbExportBitmap) + { + BitmapEx aBitmapEx(device->GetBitmap(Point(0, 0), device->GetOutputSizePixel())); + SvFileStream aStream(filename, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream); + } + } + +public: + BackendTest() + : BootstrapFixture(true, false) + { + } + + // We need to enable tests ONE BY ONE as they fail because of backend bugs + // it is still important to have the test defined so we know the issues + // exist and we need to fix them. Consistent behaviour of our backends + // is of highest priority. + + static bool assertBackendNameNotEmpty(const OUString& name) + { + // This ensures that all backends return a valid name. + assert(!name.isEmpty()); + (void)name; + return false; + } + +// Check whether tests should fail depending on which backend is used +// (not all work). If you want to disable just a specific test +// for a specific backend, use something like +// 'if(SHOULD_ASSERT && aOutDevTest.getRenderBackendName() != "skia")'. +#define SHOULD_ASSERT \ + (assertBackendNameNotEmpty(aOutDevTest.getRenderBackendName()) \ + || aOutDevTest.getRenderBackendName() == "skia") + + void testDrawRectWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-01_rectangle_test-rectangle.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPixel() + { + vcl::test::OutputDeviceTestPixel aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-02_rectangle_test-pixel.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-03_rectangle_test-line.png", aBitmap); + + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-04_rectangle_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyLine() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-05_rectangle_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyLineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-06_rectangle_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-07_rectangle_test-polypolygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectWithPolyPolygonB2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangle(aBitmap); + exportImage("01-08_rectangle_test-polypolygon_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-01_rectangle_AA_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPixel() + { + vcl::test::OutputDeviceTestPixel aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-02_rectangle_AA_test-pixel.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-03_rectangle_AA_test-line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-04_rectangle_AA_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyLine() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-05_rectangle_AA_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyLineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-06_rectangle_AA_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-07_rectangle_AA_test-polypolygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawRectAAWithPolyPolygonB2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupRectangle(true); + auto eResult = vcl::test::OutputDeviceTestCommon::checkRectangleAA(aBitmap); + exportImage("02-08_rectangle_AA_test-polypolygon_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-01_filled_rectangle_test-rectangle_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-01_filled_rectangle_test-rectangle_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-02_filled_rectangle_test-polygon_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-02_filled_rectangle_test-polygon_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolyPolygon() + { + vcl::test::OutputDeviceTestPolyPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-03_filled_rectangle_test-polypolygon_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-03_filled_rectangle_test-polypolygon_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawFilledRectWithPolyPolygon2D() + { + vcl::test::OutputDeviceTestPolyPolygonB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupFilledRectangle(false); + auto eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, false); + exportImage("03-04_filled_rectangle_test-polypolygon_b2d_noline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + aBitmap = aOutDevTest.setupFilledRectangle(true); + eResult = vcl::test::OutputDeviceTestCommon::checkFilledRectangle(aBitmap, true); + exportImage("03-04_filled_rectangle_test-polypolygon_b2d_line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolygon() + { + vcl::test::OutputDeviceTestPolygon aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-01_diamond_test-polygon.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-02_diamond_test-line.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolyline() + { + vcl::test::OutputDeviceTestPolyLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-03_diamond_test-polyline.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawDiamondWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDiamond(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkDiamond(aBitmap); + exportImage("04-04_diamond_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_NONE(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertRectangle(aBitmap); + exportImage("05-01_invert_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertN50WithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_N50(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertN50Rectangle(aBitmap); + exportImage("05-02_invert_N50_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawInvertTrackFrameWithRectangle() + { + vcl::test::OutputDeviceTestRect aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupInvert_TrackFrame(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkInvertTrackFrameRectangle(aBitmap); + exportImage("05-03_invert_TrackFrame_test-rectangle.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBezierWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupBezier(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap); + exportImage("06-01_bezier_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBezierAAWithPolylineB2D() + { + vcl::test::OutputDeviceTestPolyLineB2D aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupAABezier(); + auto eResult = vcl::test::OutputDeviceTestCommon::checkBezier(aBitmap); + exportImage("07-01_bezier_AA_test-polyline_b2d.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBitmap() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmap(); + exportImage("08-01_bitmap_test.png", aBitmap); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawTransformedBitmap() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawTransformedBitmap(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkTransformedBitmap(aBitmap); + exportImage("08-02_transformed_bitmap_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBitmapExWithAlpha() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawBitmapExWithAlpha(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkBitmapExWithAlpha(aBitmap); + exportImage("08-03_bitmapex_with_alpha_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawMask() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDrawMask(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkMask(aBitmap); + exportImage("08-04_mask_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawBlend() + { + vcl::test::OutputDeviceTestBitmap aOutDevTest; + BitmapEx aBitmapEx = aOutDevTest.setupDrawBlend(); + auto eResult = vcl::test::OutputDeviceTestBitmap::checkBlend(aBitmapEx); + exportImage("08-05_blend_test.png", aBitmapEx); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDrawXor() + { + vcl::test::OutputDeviceTestAnotherOutDev aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupXOR(); + auto eResult = vcl::test::OutputDeviceTestAnotherOutDev::checkXOR(aBitmap); + exportImage("08-06_xor_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipRectangle() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipRectangle(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-01_clip_rectangle_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-02_clip_polygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipPolyPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipPolyPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-03_clip_polypolygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testClipB2DPolyPolygon() + { + vcl::test::OutputDeviceTestClip aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupClipB2DPolyPolygon(); + auto eResult = vcl::test::OutputDeviceTestClip::checkClip(aBitmap); + exportImage("09-04_clip_b2dpolypolygon_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testDashedLine() + { + vcl::test::OutputDeviceTestLine aOutDevTest; + Bitmap aBitmap = aOutDevTest.setupDashedLine(); + auto eResult = vcl::test::OutputDeviceTestLine::checkDashedLine(aBitmap); + exportImage("10-01_dashed_line_test.png", aBitmap); + if (SHOULD_ASSERT) + CPPUNIT_ASSERT(eResult != vcl::test::TestResult::Failed); + } + + void testTdf124848() + { + ScopedVclPtr device = VclPtr::Create(DeviceFormat::DEFAULT); + device->SetOutputSizePixel(Size(100, 100)); + device->SetBackground(Wallpaper(COL_WHITE)); + device->Erase(); + device->SetAntialiasing(AntialiasingFlags::EnableB2dDraw); + device->SetLineColor(COL_BLACK); + basegfx::B2DHomMatrix matrix; + // DrawPolyLine() would apply the whole matrix to the line width, making it negative + // in case of a larger rotation. + matrix.rotate(M_PI); //180 degrees + matrix.translate(100, 100); + CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix, + basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } }, + 100, 0, nullptr, basegfx::B2DLineJoin::Miter)); + exportDevice("/tmp/tdf124848-1.png", device); + // 100px wide line should fill the entire width of the upper half + CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(2, 2))); + + // Also check hairline. + device->Erase(); + CPPUNIT_ASSERT(device->DrawPolyLineDirect(matrix, + basegfx::B2DPolygon{ { 50, 50 }, { 50, 100 } }, 0, + 0, nullptr, basegfx::B2DLineJoin::Miter)); + exportDevice("/tmp/tdf124848-2.png", device); + // 1px wide + CPPUNIT_ASSERT_EQUAL(COL_BLACK, device->GetPixel(Point(50, 20))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(49, 20))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(51, 20))); + } + + CPPUNIT_TEST_SUITE(BackendTest); + CPPUNIT_TEST(testDrawRectWithRectangle); + CPPUNIT_TEST(testDrawRectWithPixel); + CPPUNIT_TEST(testDrawRectWithLine); + CPPUNIT_TEST(testDrawRectWithPolygon); + CPPUNIT_TEST(testDrawRectWithPolyLine); + CPPUNIT_TEST(testDrawRectWithPolyLineB2D); + CPPUNIT_TEST(testDrawRectWithPolyPolygon); + CPPUNIT_TEST(testDrawRectWithPolyPolygonB2D); + + CPPUNIT_TEST(testDrawRectAAWithRectangle); + CPPUNIT_TEST(testDrawRectAAWithPixel); + CPPUNIT_TEST(testDrawRectAAWithLine); + CPPUNIT_TEST(testDrawRectAAWithPolygon); + CPPUNIT_TEST(testDrawRectAAWithPolyLine); + CPPUNIT_TEST(testDrawRectAAWithPolyLineB2D); + CPPUNIT_TEST(testDrawRectAAWithPolyPolygon); + CPPUNIT_TEST(testDrawRectAAWithPolyPolygonB2D); + + CPPUNIT_TEST(testDrawFilledRectWithRectangle); + CPPUNIT_TEST(testDrawFilledRectWithPolygon); + CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon); + CPPUNIT_TEST(testDrawFilledRectWithPolyPolygon2D); + + CPPUNIT_TEST(testDrawDiamondWithPolygon); + CPPUNIT_TEST(testDrawDiamondWithLine); + CPPUNIT_TEST(testDrawDiamondWithPolyline); + CPPUNIT_TEST(testDrawDiamondWithPolylineB2D); + + CPPUNIT_TEST(testDrawInvertWithRectangle); + CPPUNIT_TEST(testDrawInvertN50WithRectangle); + CPPUNIT_TEST(testDrawInvertTrackFrameWithRectangle); + + CPPUNIT_TEST(testDrawBezierWithPolylineB2D); + CPPUNIT_TEST(testDrawBezierAAWithPolylineB2D); + + CPPUNIT_TEST(testDrawBitmap); + CPPUNIT_TEST(testDrawTransformedBitmap); + CPPUNIT_TEST(testDrawBitmapExWithAlpha); + CPPUNIT_TEST(testDrawMask); + CPPUNIT_TEST(testDrawBlend); + CPPUNIT_TEST(testDrawXor); + + CPPUNIT_TEST(testClipRectangle); + CPPUNIT_TEST(testClipPolygon); + CPPUNIT_TEST(testClipPolyPolygon); + CPPUNIT_TEST(testClipB2DPolyPolygon); + + CPPUNIT_TEST(testDashedLine); + + CPPUNIT_TEST(testTdf124848); + + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BackendTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapExTest.cxx b/vcl/qa/cppunit/BitmapExTest.cxx new file mode 100644 index 000000000..23f40f001 --- /dev/null +++ b/vcl/qa/cppunit/BitmapExTest.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace +{ +class BitmapExTest : public CppUnit::TestFixture +{ + void testGetPixelColor24_8(); + void testGetPixelColor32(); + void testTransformBitmapEx(); + + CPPUNIT_TEST_SUITE(BitmapExTest); + CPPUNIT_TEST(testGetPixelColor24_8); + CPPUNIT_TEST(testGetPixelColor32); + CPPUNIT_TEST(testTransformBitmapEx); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapExTest::testGetPixelColor24_8() +{ + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + AlphaMask aMask(Size(3, 3)); + { + AlphaScopedWriteAccess pWriteAccess(aMask); + pWriteAccess->Erase(Color(0x00, 0xAA, 0xAA, 0xAA)); + } + + BitmapEx aBitmapEx(aBitmap, aMask); + + CPPUNIT_ASSERT_EQUAL(Color(0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0)); +} + +void BitmapExTest::testGetPixelColor32() +{ + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (!pBackendCapabilities->mbSupportsBitmap32) + return; + + Bitmap aBitmap(Size(3, 3), 32); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0xAA, 0x00, 0xFF, 0x00)); + } + + BitmapEx aBitmapEx(aBitmap); + + CPPUNIT_ASSERT_EQUAL(Color(0xAA, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(0, 0)); +} + +void BitmapExTest::testTransformBitmapEx() +{ + Bitmap aBitmap(Size(16, 16), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(i, j, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(M_PI / 2); + BitmapEx aTransformed = aBitmapEx.TransformBitmapEx(16, 16, aMatrix); + aBitmap = aTransformed.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + BitmapColor aColor = pAccess->GetPixel(i, j); + std::stringstream ss; + ss << "Color is expected to be white or black, is '" << aColor.AsRGBHexString() << "'"; + // Without the accompanying fix in place, this test would have failed with: + // - Expression: aColor == COL_WHITE || aColor == COL_BLACK + // - Color is expected to be white or black, is 'bfbfbf' + // i.e. smoothing introduced noise for a simple 90 deg rotation. + CPPUNIT_ASSERT_MESSAGE(ss.str(), aColor == COL_WHITE || aColor == COL_BLACK); + } + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapExTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx b/vcl/qa/cppunit/BitmapFilterTest.cxx new file mode 100644 index 000000000..dddfaf571 --- /dev/null +++ b/vcl/qa/cppunit/BitmapFilterTest.cxx @@ -0,0 +1,216 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +namespace +{ +constexpr bool constWriteResultBitmap(false); +constexpr bool constEnablePerformanceTest(false); + +class BitmapFilterTest : public test::BootstrapFixture +{ +public: + BitmapFilterTest() + : test::BootstrapFixture(true, false) + { + } + + void testBlurCorrectness(); + void testBasicMorphology(); + void testPerformance(); + + CPPUNIT_TEST_SUITE(BitmapFilterTest); + CPPUNIT_TEST(testBlurCorrectness); + CPPUNIT_TEST(testBasicMorphology); + CPPUNIT_TEST(testPerformance); + CPPUNIT_TEST_SUITE_END(); + +private: + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("vcl/qa/cppunit/data/") + sFileName; + } + + BitmapEx loadBitmap(const OUString& sFileName) + { + Graphic aGraphic; + const OUString aURL(getFullUrl(sFileName)); + SvFileStream aFileStream(aURL, StreamMode::READ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + ErrCode aResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aResult); + return aGraphic.GetBitmapEx(); + } + + template // handle both Bitmap and BitmapEx + void savePNG(const OUString& sWhere, const BitmapT& rBmp) + { + SvFileStream aStream(sWhere, StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(rBmp, aStream); + } +}; + +void BitmapFilterTest::testBlurCorrectness() +{ + // Setup test bitmap + Size aSize(41, 31); + Bitmap aBitmap24Bit(aSize, 24); + + ScanlineFormat scanlineFormat = ScanlineFormat::NONE; + sal_uInt16 nBPP = aBitmap24Bit.GetBitCount(); + + { + long aMargin1 = 1; + long aMargin2 = 3; + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + scanlineFormat = aWriteAccess->GetScanlineFormat(); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + + tools::Rectangle aRectangle1(aMargin1, aMargin1, aSize.Width() - 1 - aMargin1, + aSize.Height() - 1 - aMargin1); + + tools::Rectangle aRectangle2(aMargin2, aMargin2, aSize.Width() - 1 - aMargin2, + aSize.Height() - 1 - aMargin2); + + tools::Rectangle aRectangle3(aSize.Width() / 2, aSize.Height() / 2, aSize.Width() / 2, + aSize.Height() / 2); + + aWriteAccess->DrawRect(aRectangle1); + aWriteAccess->DrawRect(aRectangle2); + aWriteAccess->DrawRect(aRectangle3); + } + + if (constWriteResultBitmap) + { + savePNG("~/blurBefore.png", aBitmap24Bit); + } + + // Perform blur + BitmapFilterStackBlur aBlurFilter(2); + aBitmap24Bit = aBlurFilter.filter(aBitmap24Bit); + + // Check the result + + if (constWriteResultBitmap) + { + savePNG("~/blurAfter.png", aBitmap24Bit); + } + + // Check blurred bitmap parameters + CPPUNIT_ASSERT_EQUAL(static_cast(41), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(31), aBitmap24Bit.GetSizePixel().Height()); + + CPPUNIT_ASSERT_EQUAL(nBPP, aBitmap24Bit.GetBitCount()); + + // Check that the bitmap is horizontally and vertically symmetrical + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + { + Bitmap::ScopedReadAccess aReadAccess(aBitmap24Bit); + CPPUNIT_ASSERT_EQUAL(scanlineFormat, aReadAccess->GetScanlineFormat()); + } +} + +void BitmapFilterTest::testBasicMorphology() +{ + const BitmapEx aOrigBitmap = loadBitmap("testBasicMorphology.png"); + const BitmapEx aRefBitmapDilated1 = loadBitmap("testBasicMorphologyDilated1.png"); + const BitmapEx aRefBitmapDilated1Eroded1 = loadBitmap("testBasicMorphologyDilated1Eroded1.png"); + const BitmapEx aRefBitmapDilated2 = loadBitmap("testBasicMorphologyDilated2.png"); + const BitmapEx aRefBitmapDilated2Eroded1 = loadBitmap("testBasicMorphologyDilated2Eroded1.png"); + + BitmapEx aTransformBitmap = aOrigBitmap; + BitmapFilter::Filter(aTransformBitmap, BitmapDilateFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated1.GetChecksum(), aTransformBitmap.GetChecksum()); + BitmapFilter::Filter(aTransformBitmap, BitmapErodeFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated1Eroded1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated1Eroded1.GetChecksum(), aTransformBitmap.GetChecksum()); + + aTransformBitmap = aOrigBitmap; + BitmapFilter::Filter(aTransformBitmap, BitmapDilateFilter(2)); + if (constWriteResultBitmap) + savePNG("~/Dilated2.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated2.GetChecksum(), aTransformBitmap.GetChecksum()); + BitmapFilter::Filter(aTransformBitmap, BitmapErodeFilter(1)); + if (constWriteResultBitmap) + savePNG("~/Dilated2Eroded1.png", aTransformBitmap); + CPPUNIT_ASSERT_EQUAL(aRefBitmapDilated2Eroded1.GetChecksum(), aTransformBitmap.GetChecksum()); +} + +void BitmapFilterTest::testPerformance() +{ + if (!constEnablePerformanceTest) + return; + + Size aSize(4000, 3000); // A rather common picture size + + // Prepare bitmap + Bitmap aBigBitmap(aSize, 24); + { + long aMargin = 500; + BitmapScopedWriteAccess aWriteAccess(aBigBitmap); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + aWriteAccess->SetFillColor(COL_BLACK); + tools::Rectangle aRectangle(aMargin, aMargin, aSize.Width() - 1 - aMargin, + aSize.Height() - 1 - aMargin); + + aWriteAccess->DrawRect(aRectangle); + } + + int nIterations = 10; + auto start = std::chrono::high_resolution_clock::now(); + Bitmap aResult; + for (int i = 0; i < nIterations; i++) + { + BitmapFilterStackBlur aBlurFilter(250); + aResult = aBlurFilter.filter(aBigBitmap); + } + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = (end - start) / nIterations; + + if (constWriteResultBitmap) + { + std::unique_ptr pStream( + new SvFileStream("~/BlurBigPerformance.png", StreamMode::WRITE | StreamMode::TRUNC)); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aResult, *pStream); + + pStream.reset(new SvFileStream("~/BlurBigPerformance.txt", StreamMode::WRITE)); + pStream->WriteOString("Blur average time: "); + pStream->WriteOString(OString::number( + std::chrono::duration_cast(elapsed).count())); + pStream->WriteOString("\n"); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapFilterTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapProcessorTest.cxx b/vcl/qa/cppunit/BitmapProcessorTest.cxx new file mode 100644 index 000000000..2a628285d --- /dev/null +++ b/vcl/qa/cppunit/BitmapProcessorTest.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace +{ + +class BitmapProcessorTest : public CppUnit::TestFixture +{ + void testDisabledImage(); + + CPPUNIT_TEST_SUITE(BitmapProcessorTest); + CPPUNIT_TEST(testDisabledImage); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapProcessorTest::testDisabledImage() +{ + { + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + BitmapEx aBitmapEx(aBitmap); + BitmapDisabledImageFilter aDisabledImageFilter; + BitmapEx aDisabledBitmapEx(aDisabledImageFilter.execute(aBitmapEx)); + Bitmap aDisabledBitmap(aDisabledBitmapEx.GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aDisabledBitmap); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00C5C5C5), aColor); + } + } + + { + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x00, 0x00, 0xFF, 0x00)); + } + AlphaMask aMask(Size(3, 3)); + { + AlphaScopedWriteAccess pWriteAccess(aMask); + pWriteAccess->Erase(Color(0x00, 0xAA, 0xAA, 0xAA)); + } + + BitmapEx aBitmapEx(aBitmap, aMask); + BitmapDisabledImageFilter aDisabledImageFilter; + BitmapEx aDisabledBitmapEx(aDisabledImageFilter.execute(aBitmapEx)); + + Bitmap aDisabledBitmap(aDisabledBitmapEx.GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aDisabledBitmap); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00C5C5C5), aColor); + } + AlphaMask aDisabledAlphaMask(aDisabledBitmapEx.GetAlpha()); + { + AlphaMask::ScopedReadAccess pReadAccess(aDisabledAlphaMask); + Color aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x0000AA), aColor); + } + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapProcessorTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapScaleTest.cxx b/vcl/qa/cppunit/BitmapScaleTest.cxx new file mode 100644 index 000000000..b804cd1bf --- /dev/null +++ b/vcl/qa/cppunit/BitmapScaleTest.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace +{ +class BitmapScaleTest : public CppUnit::TestFixture +{ + void testScale(); + void testScale2(); + void testScaleSymmetry(); + + CPPUNIT_TEST_SUITE(BitmapScaleTest); + CPPUNIT_TEST(testScale); + CPPUNIT_TEST(testScale2); + CPPUNIT_TEST(testScaleSymmetry); + CPPUNIT_TEST_SUITE_END(); +}; + +bool checkBitmapColor(Bitmap const& rBitmap, Color const& rExpectedColor) +{ + bool bResult = true; + Bitmap aBitmap(rBitmap); + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + long nHeight = pReadAccess->Height(); + long nWidth = pReadAccess->Width(); + for (long y = 0; y < nHeight; ++y) + { + Scanline pScanlineRead = pReadAccess->GetScanline(y); + for (long x = 0; x < nWidth; ++x) + { + Color aColor = pReadAccess->GetPixelFromData(pScanlineRead, x); + if (aColor != rExpectedColor) + bResult = false; + } + } + + return bResult; +} + +void assertColorsAreSimilar(int maxDifference, const std::string& message, + const BitmapColor& expected, const BitmapColor& actual) +{ + // Check that the two colors match or are reasonably similar. + if (expected == actual) + return; + if (abs(expected.GetRed() - actual.GetRed()) <= maxDifference + && abs(expected.GetGreen() - actual.GetGreen()) <= maxDifference + && abs(expected.GetBlue() - actual.GetBlue()) <= maxDifference + && abs(expected.GetAlpha() - actual.GetAlpha()) <= maxDifference) + { + return; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual); +} + +void assertColorsAreSimilar(int maxDifference, int line, const BitmapColor& expected, + const BitmapColor& actual) +{ + std::stringstream stream; + stream << "Line: " << line; + assertColorsAreSimilar(maxDifference, stream.str(), expected, actual); +} + +void BitmapScaleTest::testScale() +{ + const bool bExportBitmap(false); + using tools::Rectangle; + + static const BmpScaleFlag scaleMethods[] + = { BmpScaleFlag::Default, BmpScaleFlag::Fast, BmpScaleFlag::BestQuality, + BmpScaleFlag::Interpolate, BmpScaleFlag::Lanczos, BmpScaleFlag::BiCubic, + BmpScaleFlag::BiLinear }; + for (BmpScaleFlag scaleMethod : scaleMethods) + { + struct ScaleSize + { + Size srcSize; + Size destSize; + }; + static const ScaleSize scaleSizes[] + = { // test no-op + { Size(16, 16), Size(16, 16) }, + // powers of 2 (OpenGL may use texture atlas) + { Size(16, 16), Size(14, 14) }, + { Size(14, 14), Size(16, 16) }, // both upscaling and downscaling + // "random" sizes + { Size(18, 18), Size(14, 14) }, + { Size(14, 14), Size(18, 18) }, + // different x/y ratios + { Size(16, 30), Size(14, 18) }, + { Size(14, 18), Size(16, 30) }, + // ratio larger than 16 (triggers different paths in some OpenGL algorithms) + { Size(18 * 20, 18 * 20), Size(14, 14) }, + { Size(14, 14), Size(18 * 20, 18 * 20) } + }; + for (const ScaleSize& scaleSize : scaleSizes) + { + OString testStr = "Testing scale (" + scaleSize.srcSize.toString() + ")->(" + + scaleSize.destSize.toString() + "), method " + + OString::number(static_cast(scaleMethod)); + fprintf(stderr, "%s\n", testStr.getStr()); + Bitmap bitmap(scaleSize.srcSize, 24); + { + // Fill each quarter of the source bitmap with a different color, + // and center with yet another color. + BitmapScopedWriteAccess writeAccess(bitmap); + const int halfW = scaleSize.srcSize.getWidth() / 2; + const int halfH = scaleSize.srcSize.getHeight() / 2; + writeAccess->SetFillColor(COL_GREEN); + writeAccess->FillRect(Rectangle(Point(0, 0), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_RED); + writeAccess->FillRect(Rectangle(Point(0, halfH), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_YELLOW); + writeAccess->FillRect(Rectangle(Point(halfW, 0), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_BLACK); + writeAccess->FillRect(Rectangle(Point(halfW, halfH), Size(halfW, halfH))); + writeAccess->SetFillColor(COL_BLUE); + writeAccess->FillRect(Rectangle(Point(halfW / 2, halfH / 2), Size(halfW, halfH))); + } + if (bExportBitmap) + { + SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(bitmap, aStream); + } + CPPUNIT_ASSERT(bitmap.Scale(scaleSize.destSize, scaleMethod)); + if (bExportBitmap) + { + SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(bitmap, aStream); + } + CPPUNIT_ASSERT_EQUAL(scaleSize.destSize, bitmap.GetSizePixel()); + { + // Scaling should keep each quarter of the resulting bitmap have the same color, + // so check that color in each corner of the result bitmap is the same color, + // or reasonably close (some algorithms may alter the color very slightly). + BitmapReadAccess readAccess(bitmap); + const int lastW = scaleSize.destSize.getWidth() - 1; + const int lastH = scaleSize.destSize.getHeight() - 1; + assertColorsAreSimilar(2, __LINE__, COL_GREEN, readAccess.GetColor(0, 0)); + assertColorsAreSimilar(2, __LINE__, COL_RED, readAccess.GetColor(lastH, 0)); + assertColorsAreSimilar(2, __LINE__, COL_YELLOW, readAccess.GetColor(0, lastW)); + assertColorsAreSimilar(2, __LINE__, COL_BLACK, readAccess.GetColor(lastH, lastW)); + assertColorsAreSimilar(2, __LINE__, COL_BLUE, + readAccess.GetColor(lastH / 2, lastW / 2)); + } + } + } +} + +void BitmapScaleTest::testScale2() +{ + const bool bExportBitmap(false); + + Bitmap aBitmap24Bit(Size(4096, 4096), 24); + CPPUNIT_ASSERT_EQUAL(static_cast(24), aBitmap24Bit.GetBitCount()); + Color aBitmapColor = COL_YELLOW; + { + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + aWriteAccess->Erase(aBitmapColor); + } + + if (bExportBitmap) + { + SvFileStream aStream("scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } + + // Scale - 65x65 + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Height()); + Bitmap aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(65, 65)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_65x65.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast(65), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(65), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); + + // Scale - 64x64 + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Height()); + aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(64, 64)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_64x64.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast(64), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(64), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); + + // Scale - 63x63 + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(4096), aBitmap24Bit.GetSizePixel().Height()); + aScaledBitmap = aBitmap24Bit; + aScaledBitmap.Scale(Size(63, 63)); + + if (bExportBitmap) + { + SvFileStream aStream("scale_after_63x63.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aScaledBitmap, aStream); + } + + CPPUNIT_ASSERT_EQUAL(static_cast(63), aScaledBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(63), aScaledBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT(checkBitmapColor(aScaledBitmap, aBitmapColor)); +} + +void BitmapScaleTest::testScaleSymmetry() +{ + const bool bExportBitmap(false); + + Bitmap aBitmap24Bit(Size(10, 10), 24); + CPPUNIT_ASSERT_EQUAL(static_cast(24), aBitmap24Bit.GetBitCount()); + + { + BitmapScopedWriteAccess aWriteAccess(aBitmap24Bit); + aWriteAccess->Erase(COL_WHITE); + aWriteAccess->SetLineColor(COL_BLACK); + aWriteAccess->DrawRect(tools::Rectangle(1, 1, 8, 8)); + aWriteAccess->DrawRect(tools::Rectangle(3, 3, 6, 6)); + } + + BitmapSymmetryCheck aBitmapSymmetryCheck; + + CPPUNIT_ASSERT_EQUAL(static_cast(10), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(10), aBitmap24Bit.GetSizePixel().Height()); + + // Check symmetry of the bitmap + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + if (bExportBitmap) + { + SvFileStream aStream("~/scale_before.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } + + aBitmap24Bit.Scale(2, 2, BmpScaleFlag::Fast); + + CPPUNIT_ASSERT_EQUAL(static_cast(20), aBitmap24Bit.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(static_cast(20), aBitmap24Bit.GetSizePixel().Height()); + + // After scaling the bitmap should still be symmetrical. This check guarantees that + // scaling doesn't misalign the bitmap. + CPPUNIT_ASSERT(BitmapSymmetryCheck::check(aBitmap24Bit)); + + if (bExportBitmap) + { + SvFileStream aStream("~/scale_after.png", StreamMode::WRITE | StreamMode::TRUNC); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + rFilter.compressAsPNG(aBitmap24Bit, aStream); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapScaleTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx new file mode 100644 index 000000000..640c477e3 --- /dev/null +++ b/vcl/qa/cppunit/BitmapTest.cxx @@ -0,0 +1,660 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#if HAVE_FEATURE_OPENGL +#include +#endif +#include +#include + +#include + +#include +#include +#include + +namespace +{ +class BitmapTest : public CppUnit::TestFixture +{ + void testCreation(); + void testEmpty(); + void testMonochrome(); + void testN4Greyscale(); + void testN8Greyscale(); + void testConvert(); + void testCRC(); + void testGreyPalette(); + void testCustom8BitPalette(); + void testErase(); + void testBitmap32(); + void testOctree(); + + CPPUNIT_TEST_SUITE(BitmapTest); + CPPUNIT_TEST(testCreation); + CPPUNIT_TEST(testEmpty); + CPPUNIT_TEST(testMonochrome); + CPPUNIT_TEST(testConvert); + CPPUNIT_TEST(testN4Greyscale); + CPPUNIT_TEST(testN8Greyscale); + CPPUNIT_TEST(testCRC); + CPPUNIT_TEST(testGreyPalette); + CPPUNIT_TEST(testCustom8BitPalette); + CPPUNIT_TEST(testErase); + CPPUNIT_TEST(testBitmap32); + CPPUNIT_TEST(testOctree); + CPPUNIT_TEST_SUITE_END(); +}; + +void assertColorsAreSimilar(int maxDifference, const std::string& message, + const BitmapColor& expected, const BitmapColor& actual) +{ + // Check that the two colors match or are reasonably similar. + if (expected == actual) + return; + if (abs(expected.GetRed() - actual.GetRed()) <= maxDifference + && abs(expected.GetGreen() - actual.GetGreen()) <= maxDifference + && abs(expected.GetBlue() - actual.GetBlue()) <= maxDifference + && abs(expected.GetAlpha() - actual.GetAlpha()) <= maxDifference) + { + return; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual); +} + +void BitmapTest::testCreation() +{ + { + Bitmap aBmp; + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(0), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(0), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Not empty", aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast(0), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(1), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast(0), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 1); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast(1), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(2), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast(12), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 4); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast(4), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(16), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast(50), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 8); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast(8), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(256), aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast(100), + aBmp.GetSizeBytes()); + } + + { + Bitmap aBmp(Size(10, 10), 24); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", static_cast(24), + aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(16777216), + aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", static_cast(300), + aBmp.GetSizeBytes()); + } + + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (pBackendCapabilities->mbSupportsBitmap32) + { + Bitmap aBmp(Size(10, 10), 32); + Size aSize = aBmp.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong width", static_cast(10), aSize.Width()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong height", static_cast(10), aSize.Height()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong pref size", Size(), aBmp.GetPrefSize()); + CPPUNIT_ASSERT_MESSAGE("Empty bitmap", !aBmp.IsEmpty()); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong bit count", sal_uInt16(32), aBmp.GetBitCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong color count", sal_Int64(4294967296ull), + aBmp.GetColorCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong byte size", sal_uLong(400), aBmp.GetSizeBytes()); + } +} + +void BitmapTest::testEmpty() +{ + Bitmap aBitmap(Size(10, 10), 8); + aBitmap.Erase(COL_LIGHTGRAYBLUE); + + CPPUNIT_ASSERT(!aBitmap.IsEmpty()); + + aBitmap.SetEmpty(); + CPPUNIT_ASSERT(aBitmap.IsEmpty()); +} + +Bitmap createTestBitmap() +{ + Bitmap aBmp(Size(4, 4), 24); + BitmapWriteAccess aBmpAccess(aBmp); + + // row 1 + aBmpAccess.SetPixel(0, 0, BitmapColor(COL_BLACK)); + aBmpAccess.SetPixel(0, 1, BitmapColor(COL_BLUE)); + aBmpAccess.SetPixel(0, 2, BitmapColor(COL_GREEN)); + aBmpAccess.SetPixel(0, 3, BitmapColor(COL_CYAN)); + + // row 2 + aBmpAccess.SetPixel(1, 0, BitmapColor(COL_RED)); + aBmpAccess.SetPixel(1, 1, BitmapColor(COL_MAGENTA)); + aBmpAccess.SetPixel(1, 2, BitmapColor(COL_BROWN)); + aBmpAccess.SetPixel(1, 3, BitmapColor(COL_GRAY)); + + // row 3 + aBmpAccess.SetPixel(2, 0, BitmapColor(COL_LIGHTGRAY)); + aBmpAccess.SetPixel(2, 1, BitmapColor(COL_LIGHTBLUE)); + aBmpAccess.SetPixel(2, 2, BitmapColor(COL_LIGHTGREEN)); + aBmpAccess.SetPixel(2, 3, BitmapColor(COL_LIGHTCYAN)); + + // row 4 + aBmpAccess.SetPixel(3, 0, BitmapColor(COL_LIGHTRED)); + aBmpAccess.SetPixel(3, 1, BitmapColor(COL_LIGHTMAGENTA)); + aBmpAccess.SetPixel(3, 2, BitmapColor(COL_YELLOW)); + aBmpAccess.SetPixel(3, 3, BitmapColor(COL_WHITE)); + + return aBmp; +} + +void BitmapTest::testMonochrome() +{ + Bitmap aBmp = createTestBitmap(); + + BitmapEx aBmpEx(aBmp); + BitmapFilter::Filter(aBmpEx, BitmapMonochromeFilter(63)); + aBmp = aBmpEx.GetBitmap(); + BitmapReadAccess aBmpReadAccess(aBmp); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(0, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(0, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(0, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(1, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(1, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(1, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(1, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong monochrome value", BitmapColor(COL_BLACK), + aBmpReadAccess.GetColor(2, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(2, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong monochrome value", + BitmapColor(COL_WHITE), aBmpReadAccess.GetColor(3, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong monochrome value", BitmapColor(COL_WHITE), + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testN4Greyscale() +{ + Bitmap aBmp = createTestBitmap(); + BitmapPalette aGreyscalePalette = Bitmap::GetGreyPalette(16); + + aBmp.Convert(BmpConversion::N4BitGreys); + BitmapReadAccess aBmpReadAccess(aBmp); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Black pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green pixel wrong 8-bit greyscale value", aGreyscalePalette[4], + aBmpReadAccess.GetColor(0, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette[5], + aBmpReadAccess.GetColor(0, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red pixel wrong 8-bit greyscale value", aGreyscalePalette[2], + aBmpReadAccess.GetColor(1, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette[3], + aBmpReadAccess.GetColor(1, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Brown pixel wrong 8-bit greyscale value", aGreyscalePalette[7], + aBmpReadAccess.GetColor(1, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Gray pixel wrong 8-bit greyscale value", aGreyscalePalette[8], + aBmpReadAccess.GetColor(1, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light gray pixel wrong 8-bit greyscale value", + aGreyscalePalette[12], aBmpReadAccess.GetColor(2, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light blue pixel wrong 8-bit greyscale value", + aGreyscalePalette[1], aBmpReadAccess.GetColor(2, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light green pixel wrong 8-bit greyscale value", + aGreyscalePalette[9], aBmpReadAccess.GetColor(2, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light cyan pixel wrong 8-bit greyscale value", + aGreyscalePalette[11], aBmpReadAccess.GetColor(2, 3)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light red pixel wrong 8-bit greyscale value", + aGreyscalePalette[4], aBmpReadAccess.GetColor(3, 0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Light magenta pixel wrong 8-bit greyscale value", + aGreyscalePalette[6], aBmpReadAccess.GetColor(3, 1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette[14], + aBmpReadAccess.GetColor(3, 2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("White pixel wrong 8-bit greyscale value", aGreyscalePalette[15], + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testN8Greyscale() +{ + Bitmap aBmp = createTestBitmap(); + BitmapPalette aGreyscalePalette = Bitmap::GetGreyPalette(256); + + aBmp.Convert(BmpConversion::N8BitGreys); + BitmapReadAccess aBmpReadAccess(aBmp); + + assertColorsAreSimilar(1, "Black pixel wrong 8-bit greyscale value", aGreyscalePalette[0], + aBmpReadAccess.GetColor(0, 0)); + assertColorsAreSimilar(1, "Blue pixel wrong 8-bit greyscale value", aGreyscalePalette[14], + aBmpReadAccess.GetColor(0, 1)); + assertColorsAreSimilar(1, "Green pixel wrong 8-bit greyscale value", aGreyscalePalette[75], + aBmpReadAccess.GetColor(0, 2)); + assertColorsAreSimilar(1, "Cyan pixel wrong 8-bit greyscale value", aGreyscalePalette[89], + aBmpReadAccess.GetColor(0, 3)); + assertColorsAreSimilar(1, "Red pixel wrong 8-bit greyscale value", aGreyscalePalette[38], + aBmpReadAccess.GetColor(1, 0)); + assertColorsAreSimilar(1, "Magenta pixel wrong 8-bit greyscale value", aGreyscalePalette[52], + aBmpReadAccess.GetColor(1, 1)); + assertColorsAreSimilar(1, "Brown pixel wrong 8-bit greyscale value", aGreyscalePalette[114], + aBmpReadAccess.GetColor(1, 2)); + assertColorsAreSimilar(1, "Gray pixel wrong 8-bit greyscale value", aGreyscalePalette[128], + aBmpReadAccess.GetColor(1, 3)); + assertColorsAreSimilar(1, "Light gray pixel wrong 8-bit greyscale value", + aGreyscalePalette[192], aBmpReadAccess.GetColor(2, 0)); + assertColorsAreSimilar(1, "Light blue pixel wrong 8-bit greyscale value", aGreyscalePalette[27], + aBmpReadAccess.GetColor(2, 1)); + assertColorsAreSimilar(1, "Light green pixel wrong 8-bit greyscale value", + aGreyscalePalette[150], aBmpReadAccess.GetColor(2, 2)); + assertColorsAreSimilar(1, "Light cyan pixel wrong 8-bit greyscale value", + aGreyscalePalette[178], aBmpReadAccess.GetColor(2, 3)); + assertColorsAreSimilar(1, "Light red pixel wrong 8-bit greyscale value", aGreyscalePalette[76], + aBmpReadAccess.GetColor(3, 0)); + assertColorsAreSimilar(1, "Light magenta pixel wrong 8-bit greyscale value", + aGreyscalePalette[104], aBmpReadAccess.GetColor(3, 1)); + assertColorsAreSimilar(1, "Yellow pixel wrong 8-bit greyscale value", aGreyscalePalette[227], + aBmpReadAccess.GetColor(3, 2)); + assertColorsAreSimilar(1, "White pixel wrong 8-bit greyscale value", aGreyscalePalette[255], + aBmpReadAccess.GetColor(3, 3)); +} + +void BitmapTest::testConvert() +{ + Bitmap aBitmap(Size(10, 10), 8); + + aBitmap.Erase(COL_LIGHTGRAYBLUE); + + CPPUNIT_ASSERT_EQUAL(static_cast(8), aBitmap.GetBitCount()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(static_cast(8), pReadAccess->GetBitCount()); +#if defined MACOSX || defined IOS + //it would be nice to find and change the stride for quartz to be the same as everyone else + CPPUNIT_ASSERT_EQUAL(static_cast(10), pReadAccess->GetScanlineSize()); +#else + if (!SkiaHelper::isVCLSkiaEnabled()) +#if HAVE_FEATURE_OPENGL + if (!OpenGLHelper::isVCLOpenGLEnabled()) +#endif + CPPUNIT_ASSERT_EQUAL(static_cast(12), pReadAccess->GetScanlineSize()); +#endif + CPPUNIT_ASSERT(pReadAccess->HasPalette()); + const BitmapColor& rColor = pReadAccess->GetPaletteColor(pReadAccess->GetPixelIndex(1, 1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(rColor.GetGreen())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(rColor.GetBlue())); + } + + aBitmap.Convert(BmpConversion::N24Bit); + + CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmap.GetBitCount()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + // 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere. + CPPUNIT_ASSERT_EQUAL(static_cast(24), pReadAccess->GetBitCount()); + + if (SkiaHelper::isVCLSkiaEnabled()) // aligned to 4 bytes + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + else +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess->GetScanlineSize()); + else +#endif +#if defined LINUX || defined FREEBSD + { + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + } +#elif defined(_WIN32) + { + // GDI Scanlines padded to DWORD multiples, it seems + CPPUNIT_ASSERT_EQUAL(sal_uInt32(32), pReadAccess->GetScanlineSize()); + } +#else + { + CPPUNIT_ASSERT_EQUAL(sal_uInt32(30), pReadAccess->GetScanlineSize()); + } +#endif + + CPPUNIT_ASSERT(!pReadAccess->HasPalette()); + Color aColor = pReadAccess->GetPixel(0, 0); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetGreen())); + CPPUNIT_ASSERT_EQUAL(sal_Int32(255), sal_Int32(aColor.GetBlue())); + } +} + +typedef std::unordered_map CRCHash; + +void checkAndInsert(CRCHash& rHash, sal_uInt64 nCRC, const char* pLocation) +{ + auto it = rHash.find(nCRC); + if (it != rHash.end()) + { + OStringBuffer aBuf("CRC collision between "); + aBuf.append(pLocation); + aBuf.append(" and "); + aBuf.append(it->second); + aBuf.append(" hash is 0x"); + aBuf.append(static_cast(nCRC), 16); + CPPUNIT_FAIL(aBuf.toString().getStr()); + } + rHash[nCRC] = pLocation; +} + +void checkAndInsert(CRCHash& rHash, Bitmap const& rBmp, const char* pLocation) +{ + checkAndInsert(rHash, rBmp.GetChecksum(), pLocation); +} + +Bitmap getAsBitmap(VclPtr const& pOut) +{ + return pOut->GetBitmap(Point(), pOut->GetOutputSizePixel()); +} + +void BitmapTest::testCRC() +{ + CRCHash aCRCs; + + Bitmap aBitmap(Size(1023, 759), 24, nullptr); + aBitmap.Erase(COL_BLACK); + checkAndInsert(aCRCs, aBitmap, "black bitmap"); + aBitmap.Invert(); + checkAndInsert(aCRCs, aBitmap, "white bitmap"); + + ScopedVclPtrInstance aVDev; + aVDev->SetBackground(Wallpaper(COL_WHITE)); + aVDev->SetOutputSizePixel(Size(1023, 759)); + +#if 0 // disabled for now - oddly breaks on OS/X - but why ? + Bitmap aWhiteCheck = getAsBitmap(aVDev); + CPPUNIT_ASSERT(aCRCs.find(aWhiteCheck.GetChecksum()) != aCRCs.end()); +#endif + + // a 1x1 black & white checkerboard + aVDev->DrawCheckered(Point(), aVDev->GetOutputSizePixel(), 1, Color(0, 0, 1)); + Bitmap aChecker = getAsBitmap(aVDev); + checkAndInsert(aCRCs, aChecker, "checkerboard"); + aChecker.Invert(); + checkAndInsert(aCRCs, aChecker, "inverted checkerboard"); +} + +void BitmapTest::testGreyPalette() +{ + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast(2), + aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(255, 255, 255), aPalette[1]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast(4), + aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(85, 85, 85), aPalette[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(170, 170, 170), aPalette[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(255, 255, 255), aPalette[3]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(16); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", static_cast(16), + aPalette.GetEntryCount()); + // this is a *real* specific number of greys, incremented in units of 17 so may + // as well test them all... + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 2 wrong", BitmapColor(17, 17, 17), aPalette[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 3 wrong", BitmapColor(34, 34, 34), aPalette[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 4 wrong", BitmapColor(51, 51, 51), aPalette[3]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 5 wrong", BitmapColor(68, 68, 68), aPalette[4]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 6 wrong", BitmapColor(85, 85, 85), aPalette[5]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 7 wrong", BitmapColor(102, 102, 102), aPalette[6]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 8 wrong", BitmapColor(119, 119, 119), aPalette[7]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 9 wrong", BitmapColor(136, 136, 136), aPalette[8]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 10 wrong", BitmapColor(153, 153, 153), aPalette[9]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 11 wrong", BitmapColor(170, 170, 170), aPalette[10]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 12 wrong", BitmapColor(187, 187, 187), aPalette[11]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 13 wrong", BitmapColor(204, 204, 204), aPalette[12]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 14 wrong", BitmapColor(221, 221, 221), aPalette[13]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 15 wrong", BitmapColor(238, 238, 238), aPalette[14]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 16 wrong", BitmapColor(255, 255, 255), aPalette[15]); + } + + { + BitmapPalette aPalette = Bitmap::GetGreyPalette(256); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong number of palette entries", + static_cast(256), aPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 1 wrong", BitmapColor(0, 0, 0), aPalette[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 127 wrong", BitmapColor(127, 127, 127), aPalette[127]); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Entry 255 wrong", BitmapColor(255, 255, 255), aPalette[255]); + } +} + +void BitmapTest::testCustom8BitPalette() +{ + BitmapPalette aCustomPalette; + aCustomPalette.SetEntryCount(256); + for (sal_uInt16 i = 0; i < 256; i++) + { + aCustomPalette[i] = BitmapColor(sal_uInt8(i), sal_uInt8(0xCC), sal_uInt8(0x22)); + } + Bitmap aBitmap(Size(3, 2), 8, &aCustomPalette); + + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->SetPixelIndex(0, 0, 0); + pAccess->SetPixelIndex(0, 1, 1); + pAccess->SetPixelIndex(0, 2, 2); + + pAccess->SetPixelIndex(1, 0, 253); + pAccess->SetPixelIndex(1, 1, 254); + pAccess->SetPixelIndex(1, 2, 255); + } + + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(0, int(pAccess->GetPixelIndex(0, 0))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xCC, 0x22), pAccess->GetColor(0, 0)); + + CPPUNIT_ASSERT_EQUAL(1, int(pAccess->GetPixelIndex(0, 1))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x01, 0xCC, 0x22), pAccess->GetColor(0, 1)); + + CPPUNIT_ASSERT_EQUAL(2, int(pAccess->GetPixelIndex(0, 2))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x02, 0xCC, 0x22), pAccess->GetColor(0, 2)); + + CPPUNIT_ASSERT_EQUAL(253, int(pAccess->GetPixelIndex(1, 0))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFD, 0xCC, 0x22), pAccess->GetColor(1, 0)); + + CPPUNIT_ASSERT_EQUAL(254, int(pAccess->GetPixelIndex(1, 1))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFE, 0xCC, 0x22), pAccess->GetColor(1, 1)); + + CPPUNIT_ASSERT_EQUAL(255, int(pAccess->GetPixelIndex(1, 2))); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xCC, 0x22), pAccess->GetColor(1, 2)); + } +} + +void BitmapTest::testErase() +{ + Bitmap aBitmap(Size(3, 3), 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0x11, 0x22, 0x33)); + } + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + BitmapColor aColor(pReadAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x11, 0x22, 0x33, 0x00), aColor); + } +} + +void BitmapTest::testBitmap32() +{ + // Check backend capabilities and return from the test successfully + // if the backend doesn't support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (!pBackendCapabilities->mbSupportsBitmap32) + return; + + Bitmap aBitmap(Size(3, 3), 32); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(Color(0xFF, 0x11, 0x22, 0x33)); + pWriteAccess->SetPixel(1, 1, BitmapColor(0x44, 0xFF, 0xBB, 0x00)); + pWriteAccess->SetPixel(2, 2, BitmapColor(0x99, 0x77, 0x66, 0x55)); + } + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + BitmapColor aColor = pReadAccess->GetPixel(0, 0); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0xFF), aColor); + + aColor = pReadAccess->GetPixel(1, 1); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x44, 0xFF, 0xBB, 0x00), aColor); + + aColor = pReadAccess->GetPixel(2, 2); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x99, 0x77, 0x66, 0x55), aColor); + } +} + +void BitmapTest::testOctree() +{ + Size aSize(1000, 100); + Bitmap aBitmap(aSize, 24); + { + BitmapScopedWriteAccess pWriteAccess(aBitmap); + for (long y = 0; y < aSize.Height(); ++y) + { + for (long x = 0; x < aSize.Width(); ++x) + { + double fPercent = double(x) / double(aSize.Width()); + pWriteAccess->SetPixel(y, x, + BitmapColor(255.0 * fPercent, 64.0 + (128.0 * fPercent), + 255.0 - 255.0 * fPercent)); + } + } + } + + { + // Reduce to 1 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 1); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), aBitmapPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7e, 0x7f, 0x7f), aBitmapPalette[0]); + } + + { + // Reduce to 4 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 4); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), aBitmapPalette.GetEntryCount()); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x7f, 0x7f), aBitmapPalette[0]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x3e, 0x5f, 0xbf), aBitmapPalette[1]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x7f, 0x80, 0x7f), aBitmapPalette[2]); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xbe, 0x9f, 0x3f), aBitmapPalette[3]); + } + + { + // Reduce to 256 color + Bitmap::ScopedReadAccess pAccess(aBitmap); + Octree aOctree(*pAccess, 256); + auto aBitmapPalette = aOctree.GetPalette(); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(74), aBitmapPalette.GetEntryCount()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/FontFeatureTest.cxx b/vcl/qa/cppunit/FontFeatureTest.cxx new file mode 100644 index 000000000..e4040f35b --- /dev/null +++ b/vcl/qa/cppunit/FontFeatureTest.cxx @@ -0,0 +1,336 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include +#include +#include + +class FontFeatureTest : public test::BootstrapFixture +{ +public: + FontFeatureTest() + : BootstrapFixture(true, false) + { + } + + void testGetFontFeatures(); + void testParseFeature(); + + CPPUNIT_TEST_SUITE(FontFeatureTest); + CPPUNIT_TEST(testGetFontFeatures); + CPPUNIT_TEST(testParseFeature); + CPPUNIT_TEST_SUITE_END(); +}; + +void FontFeatureTest::testGetFontFeatures() +{ +#if HAVE_MORE_FONTS + ScopedVclPtrInstance aVDev(*Application::GetDefaultDevice(), + DeviceFormat::DEFAULT, DeviceFormat::DEFAULT); + aVDev->SetOutputSizePixel(Size(10, 10)); + + OUString aFontName("Linux Libertine G"); + CPPUNIT_ASSERT(aVDev->IsFontAvailable(aFontName)); + + vcl::Font aFont = aVDev->GetFont(); + aFont.SetFamilyName(aFontName); + aFont.SetWeight(FontWeight::WEIGHT_NORMAL); + aFont.SetItalic(FontItalic::ITALIC_NORMAL); + aFont.SetWidthType(FontWidth::WIDTH_NORMAL); + aVDev->SetFont(aFont); + + std::vector rFontFeatures; + CPPUNIT_ASSERT(aVDev->GetFontFeatures(rFontFeatures)); + + // We're interested only in defaults here + std::vector rDefaultFontFeatures; + OUString aFeaturesString; + for (vcl::font::Feature const& rFeature : rFontFeatures) + { + if (rFeature.m_aID.m_aScriptCode == vcl::font::featureCode("DFLT") + && rFeature.m_aID.m_aLanguageCode == vcl::font::featureCode("dflt")) + { + rDefaultFontFeatures.push_back(rFeature); + aFeaturesString += vcl::font::featureCodeAsString(rFeature.m_aID.m_aFeatureCode) + " "; + } + } + + CPPUNIT_ASSERT_EQUAL(size_t(53), rDefaultFontFeatures.size()); + + OUString aExpectedFeaturesString = "c2sc case dlig fina frac hlig liga lnum " + "locl onum pnum sa01 sa02 sa03 sa04 sa05 " + "sa06 sa07 sa08 salt sinf smcp ss01 ss02 " + "ss03 sups tnum zero ingl cpsp lith litt " + "itlc para algn arti circ dash dbls foot " + "frsp grkn hang lng minu nfsp name quot " + "texm thou vari caps ligc "; + + CPPUNIT_ASSERT_EQUAL(aExpectedFeaturesString, aFeaturesString); + + // Check C2SC feature + { + vcl::font::Feature& rFeature = rDefaultFontFeatures[0]; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFeature.m_aID.m_aFeatureCode); + + vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("c2sc"), rFracFeatureDefinition.getCode()); + CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty()); + CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::BOOL, + rFracFeatureDefinition.getType()); + + CPPUNIT_ASSERT_EQUAL(size_t(0), rFracFeatureDefinition.getEnumParameters().size()); + } + + // Check FRAC feature + { + vcl::font::Feature& rFeature = rDefaultFontFeatures[4]; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFeature.m_aID.m_aFeatureCode); + + vcl::font::FeatureDefinition& rFracFeatureDefinition = rFeature.m_aDefinition; + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("frac"), rFracFeatureDefinition.getCode()); + CPPUNIT_ASSERT(!rFracFeatureDefinition.getDescription().isEmpty()); + CPPUNIT_ASSERT_EQUAL(vcl::font::FeatureParameterType::ENUM, + rFracFeatureDefinition.getType()); + + CPPUNIT_ASSERT_EQUAL(size_t(3), rFracFeatureDefinition.getEnumParameters().size()); + + vcl::font::FeatureParameter const& rParameter1 + = rFracFeatureDefinition.getEnumParameters()[0]; + CPPUNIT_ASSERT_EQUAL(uint32_t(0), rParameter1.getCode()); + CPPUNIT_ASSERT(!rParameter1.getDescription().isEmpty()); + + vcl::font::FeatureParameter const& rParameter2 + = rFracFeatureDefinition.getEnumParameters()[1]; + CPPUNIT_ASSERT_EQUAL(uint32_t(1), rParameter2.getCode()); + CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty()); + + vcl::font::FeatureParameter const& rParameter3 + = rFracFeatureDefinition.getEnumParameters()[2]; + CPPUNIT_ASSERT_EQUAL(uint32_t(2), rParameter3.getCode()); + CPPUNIT_ASSERT(!rParameter2.getDescription().isEmpty()); + } + + aVDev.disposeAndClear(); +#endif // HAVE_MORE_FONTS +} + +void FontFeatureTest::testParseFeature() +{ + { // No font features specified + vcl::font::FeatureParser aParser("Font name with no features"); + CPPUNIT_ASSERT_EQUAL(size_t(0), aParser.getFeatures().size()); + } + { // One feature specified, no value + vcl::font::FeatureParser aParser("Font name:abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, explicit value + vcl::font::FeatureParser aParser("Font name:abcd=5"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(5), aFeatures[0].m_nValue); + } + { // One feature specified, explicit zero value + vcl::font::FeatureParser aParser("Font name:abcd=0"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, using plus prefix + vcl::font::FeatureParser aParser("Font name:+abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, using minus prefix + vcl::font::FeatureParser aParser("Font name:-abcd"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, with empty character range + vcl::font::FeatureParser aParser("Font name:abcd[]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with empty character range + vcl::font::FeatureParser aParser("Font name:abcd[:]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with start character range + vcl::font::FeatureParser aParser("Font name:abcd[3:]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(-1), aFeatures[0].m_nEnd); + } + { // One feature specified, with end character range + vcl::font::FeatureParser aParser("Font name:abcd[:3]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range + vcl::font::FeatureParser aParser("Font name:abcd[3:6]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range + vcl::font::FeatureParser aParser("Font name:abcd[3]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(4), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and value + vcl::font::FeatureParser aParser("Font name:abcd[3:6]=2"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and 0 value + vcl::font::FeatureParser aParser("Font name:abcd[3:6]=0"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with character range and minus prefix + vcl::font::FeatureParser aParser("Font name:-abcd[3:6]"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aFeatures[0].m_nStart); + CPPUNIT_ASSERT_EQUAL(static_cast(6), aFeatures[0].m_nEnd); + } + { // One feature specified, with CSS on + vcl::font::FeatureParser aParser("Font name:\"abcd\" on"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + } + { // One feature specified, with CSS off + vcl::font::FeatureParser aParser("Font name:'abcd' off"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[0].m_nValue); + } + { // One feature specified, with CSS value + vcl::font::FeatureParser aParser("Font name:\"abcd\" 2"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(2), aFeatures[0].m_nValue); + } + { // Multiple features specified, no values + vcl::font::FeatureParser aParser("Font name:abcd&bcde&efgh"); + CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[1].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("efgh"), aFeatures[2].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[2].m_nValue); + } + { + // Multiple features specified, explicit values + // Only 4 char parameter names supported - "toolong" is too long and ignored + vcl::font::FeatureParser aParser("Font name:abcd=1&bcde=0&toolong=1&cdef=3"); + CPPUNIT_ASSERT_EQUAL(size_t(3), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("bcde"), aFeatures[1].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(0), aFeatures[1].m_nValue); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("cdef"), aFeatures[2].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(3), aFeatures[2].m_nValue); + } + { + // Special case - "lang" is parsed specially and access separately not as a feature. + + vcl::font::FeatureParser aParser("Font name:abcd=1&lang=slo"); + CPPUNIT_ASSERT_EQUAL(size_t(1), aParser.getFeatures().size()); + auto aFeatures = aParser.getFeatures(); + + CPPUNIT_ASSERT_EQUAL(vcl::font::featureCode("abcd"), aFeatures[0].m_nTag); + CPPUNIT_ASSERT_EQUAL(uint32_t(1), aFeatures[0].m_nValue); + + CPPUNIT_ASSERT_EQUAL(OUString("slo"), aParser.getLanguage()); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(FontFeatureTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicDescriptorTest.cxx b/vcl/qa/cppunit/GraphicDescriptorTest.cxx new file mode 100644 index 000000000..4ee5e96ed --- /dev/null +++ b/vcl/qa/cppunit/GraphicDescriptorTest.cxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +using namespace css; + +namespace +{ +class GraphicDescriptorTest : public CppUnit::TestFixture +{ + void testDetectPNG(); + void testDetectJPG(); + void testDetectGIF(); + + CPPUNIT_TEST_SUITE(GraphicDescriptorTest); + CPPUNIT_TEST(testDetectPNG); + CPPUNIT_TEST(testDetectJPG); + CPPUNIT_TEST(testDetectGIF); + CPPUNIT_TEST_SUITE_END(); +}; + +BitmapEx createBitmap() +{ + Bitmap aBitmap(Size(100, 100), 24); + aBitmap.Erase(COL_LIGHTRED); + + return BitmapEx(aBitmap); +} + +void createBitmapAndExportForType(SvStream& rStream, OUString const& sType) +{ + BitmapEx aBitmapEx = createBitmap(); + + uno::Sequence aFilterData; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(sType); + rGraphicFilter.ExportGraphic(aBitmapEx, "none", rStream, nFilterFormat, &aFilterData); + + rStream.Seek(STREAM_SEEK_TO_BEGIN); +} + +void GraphicDescriptorTest::testDetectPNG() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "png"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::PNG, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +void GraphicDescriptorTest::testDetectJPG() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "jpg"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::JPG, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +void GraphicDescriptorTest::testDetectGIF() +{ + SvMemoryStream aStream; + createBitmapAndExportForType(aStream, "gif"); + + GraphicDescriptor aDescriptor(aStream, nullptr); + aDescriptor.Detect(true); + + CPPUNIT_ASSERT_EQUAL(GraphicFileFormat::GIF, aDescriptor.GetFileFormat()); + + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aDescriptor.GetSizePixel().Height()); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicDescriptorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx new file mode 100644 index 000000000..1ce516bf5 --- /dev/null +++ b/vcl/qa/cppunit/GraphicFormatDetectorTest.cxx @@ -0,0 +1,416 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include + +#include + +using namespace css; + +namespace +{ +class GraphicFormatDetectorTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("/vcl/qa/cppunit/data/") + sFileName; + } + + void testDetectMET(); + void testDetectBMP(); + void testDetectWMF(); + void testDetectPCX(); + void testDetectJPG(); + void testDetectPNG(); + void testDetectGIF(); + void testDetectPSD(); + void testDetectTGA(); + void testDetectTIF(); + void testDetectXBM(); + void testDetectXPM(); + void testDetectSVG(); + void testDetectSVGZ(); + void testDetectPDF(); + void testDetectEPS(); + void testMatchArray(); + void testCheckArrayForMatchingStrings(); + + CPPUNIT_TEST_SUITE(GraphicFormatDetectorTest); + CPPUNIT_TEST(testDetectMET); + CPPUNIT_TEST(testDetectBMP); + CPPUNIT_TEST(testDetectWMF); + CPPUNIT_TEST(testDetectPCX); + CPPUNIT_TEST(testDetectJPG); + CPPUNIT_TEST(testDetectPNG); + CPPUNIT_TEST(testDetectGIF); + CPPUNIT_TEST(testDetectPSD); + CPPUNIT_TEST(testDetectTGA); + CPPUNIT_TEST(testDetectTIF); + CPPUNIT_TEST(testDetectXBM); + CPPUNIT_TEST(testDetectXPM); + CPPUNIT_TEST(testDetectSVG); + CPPUNIT_TEST(testDetectSVGZ); + CPPUNIT_TEST(testDetectPDF); + CPPUNIT_TEST(testDetectEPS); + CPPUNIT_TEST(testMatchArray); + CPPUNIT_TEST(testCheckArrayForMatchingStrings); + CPPUNIT_TEST_SUITE_END(); +}; + +void GraphicFormatDetectorTest::testDetectMET() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.met"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "MET"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkMET()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("MET"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectBMP() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.bmp"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "BMP"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkBMP()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("BMP"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectWMF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.wmf"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "WMF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkWMForEMF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("WMF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPCX() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.pcx"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PCX"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPCX()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PCX"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectJPG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.jpg"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "JPG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkJPG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("JPG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPNG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.png"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PNG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPNG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PNG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectGIF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.gif"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "GIF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkGIF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("GIF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPSD() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.psd"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PSD"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPSD()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PSD"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectTGA() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.tga"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "TGA"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkTGA()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension("TGA"); // detection is based on extension only + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("TGA"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectTIF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.tif"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "TIF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkTIF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("TIF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectXBM() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.xbm"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "XBM"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkXBM()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("XBM"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectXPM() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.xpm"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "XPM"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkXPM()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("XPM"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectSVG() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.svg"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "SVG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkSVG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("SVG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectSVGZ() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.svgz"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "SVG"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkSVG()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("SVG"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectPDF() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.pdf"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "PDF"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkPDF()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("PDF"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testDetectEPS() +{ + SvFileStream aFileStream(getFullUrl("TypeDetectionExample.eps"), StreamMode::READ); + vcl::GraphicFormatDetector aDetector(aFileStream, "EPS"); + + CPPUNIT_ASSERT(aDetector.detect()); + CPPUNIT_ASSERT(aDetector.checkEPS()); + + aFileStream.Seek(aDetector.mnStreamPosition); + + OUString rFormatExtension; + CPPUNIT_ASSERT(ImpPeekGraphicFormat(aFileStream, rFormatExtension, false)); + CPPUNIT_ASSERT_EQUAL(OUString("EPS"), rFormatExtension); +} + +void GraphicFormatDetectorTest::testMatchArray() +{ + std::string aString("\n" + "\n" + ""); + + const char* pCompleteStringPointer = aString.c_str(); + const char* pMatchPointer; + int nCheckSize = aString.size(); + + // Check beginning of the input string + pMatchPointer = vcl::matchArrayWithString(pCompleteStringPointer, nCheckSize, ""); + CPPUNIT_ASSERT(pMatchPointer != nullptr); + CPPUNIT_ASSERT_EQUAL(119, int(pMatchPointer - pCompleteStringPointer)); + CPPUNIT_ASSERT_EQUAL(true, OString(pMatchPointer).startsWith("/svg>")); + + // Check that non-existing search string + pMatchPointer = vcl::matchArrayWithString(aString.c_str(), nCheckSize, "none"); + CPPUNIT_ASSERT(pMatchPointer == nullptr); +} + +void GraphicFormatDetectorTest::testCheckArrayForMatchingStrings() +{ + std::string aString("\n" + "\n" + ""); + const char* pCompleteStringPointer = aString.c_str(); + int nCheckSize = aString.size(); + bool bResult; + + // check beginning string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check middle string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "version" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check beginning and then ending string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check ending and then beginning string + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "/svg>", "" }); + CPPUNIT_ASSERT_EQUAL(true, bResult); + + // check non-existing + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, { "none" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check non-existing on the beginning + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "none", "version", "" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); + + // check non-existing on the end + bResult = vcl::checkArrayForMatchingStrings(pCompleteStringPointer, nCheckSize, + { "", "none" }); + CPPUNIT_ASSERT_EQUAL(false, bResult); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicFormatDetectorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx b/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx new file mode 100644 index 000000000..7e5d1adcb --- /dev/null +++ b/vcl/qa/cppunit/GraphicNativeMetadataTest.cxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include +#include + +using namespace css; + +namespace +{ +class GraphicNativeMetadataTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc("/vcl/qa/cppunit/data/") + sFileName; + } + + void testReadFromGraphic(); + void testExifRotationJpeg(); + + CPPUNIT_TEST_SUITE(GraphicNativeMetadataTest); + CPPUNIT_TEST(testReadFromGraphic); + CPPUNIT_TEST(testExifRotationJpeg); + CPPUNIT_TEST_SUITE_END(); +}; + +void GraphicNativeMetadataTest::testReadFromGraphic() +{ + SvFileStream aFileStream(getFullUrl("Exif1_180.jpg"), StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + + // don't load the graphic, but try to get the metadata + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aFileStream); + + { + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + // just the metadata shouldn't make the graphic available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + } + + // now load, and it should still work the same + { + aGraphic.makeAvailable(); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + } +} + +void GraphicNativeMetadataTest::testExifRotationJpeg() +{ + { + // No rotation in metadata + SvFileStream aFileStream(getFullUrl("Exif1.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), aMetadata.getRotation()); + } + { + // Rotation 90 degree clock-wise = 270 degree counter-clock-wise + SvFileStream aFileStream(getFullUrl("Exif1_090CW.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2700), aMetadata.getRotation()); + } + { + // Rotation 180 degree + SvFileStream aFileStream(getFullUrl("Exif1_180.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(1800), aMetadata.getRotation()); + } + { + // Rotation 270 degree clock-wise = 90 degree counter-clock-wise + SvFileStream aFileStream(getFullUrl("Exif1_270CW.jpg"), StreamMode::READ); + GraphicNativeMetadata aMetadata; + aMetadata.read(aFileStream); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(900), aMetadata.getRotation()); + } +} + +} // anonymous namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicNativeMetadataTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/GraphicTest.cxx b/vcl/qa/cppunit/GraphicTest.cxx new file mode 100644 index 000000000..6a70ba921 --- /dev/null +++ b/vcl/qa/cppunit/GraphicTest.cxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_TLS_NSS +#include +#endif + +using namespace css; + +namespace +{ +class GraphicTest : public CppUnit::TestFixture +{ +public: + ~GraphicTest(); + +private: + void testUnloadedGraphic(); + void testUnloadedGraphicLoading(); + void testUnloadedGraphicWmf(); + void testUnloadedGraphicAlpha(); + void testUnloadedGraphicSizeUnit(); + void testSwapping(); + void testSwappingVectorGraphic(); + + CPPUNIT_TEST_SUITE(GraphicTest); + CPPUNIT_TEST(testUnloadedGraphic); + CPPUNIT_TEST(testUnloadedGraphicLoading); + CPPUNIT_TEST(testUnloadedGraphicWmf); + CPPUNIT_TEST(testUnloadedGraphicAlpha); + CPPUNIT_TEST(testUnloadedGraphicSizeUnit); + CPPUNIT_TEST(testSwapping); + CPPUNIT_TEST(testSwappingVectorGraphic); + CPPUNIT_TEST_SUITE_END(); +}; + +GraphicTest::~GraphicTest() +{ +#if USE_TLS_NSS + NSS_Shutdown(); +#endif +} + +BitmapEx createBitmap(bool alpha = false) +{ + Bitmap aBitmap(Size(120, 100), 24); + aBitmap.Erase(COL_LIGHTRED); + + aBitmap.SetPrefSize(Size(6000, 5000)); + aBitmap.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + + if (alpha) + { + sal_uInt8 uAlphaValue = 0x80; + AlphaMask aAlphaMask(Size(120, 100), &uAlphaValue); + + return BitmapEx(aBitmap, aAlphaMask); + } + else + { + return BitmapEx(aBitmap); + } +} + +void createBitmapAndExportForType(SvStream& rStream, OUString const& sType, bool alpha) +{ + BitmapEx aBitmapEx = createBitmap(alpha); + + uno::Sequence aFilterData; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName(sType); + rGraphicFilter.ExportGraphic(aBitmapEx, "none", rStream, nFilterFormat, &aFilterData); + + rStream.Seek(STREAM_SEEK_TO_BEGIN); +} + +Graphic makeUnloadedGraphic(OUString const& sType, bool alpha = false) +{ + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + createBitmapAndExportForType(aStream, sType, alpha); + return rGraphicFilter.ImportUnloadedGraphic(aStream); +} + +std::string toHexString(const std::vector& a) +{ + std::stringstream aStrm; + for (auto& i : a) + { + aStrm << std::setw(2) << std::setfill('0') << std::hex << static_cast(i); + } + + return aStrm.str(); +} + +std::unique_ptr createStream(OUString const& rSwapFileURL) +{ + std::unique_ptr xStream; + + try + { + xStream = ::utl::UcbStreamHelper::CreateStream( + rSwapFileURL, StreamMode::READWRITE | StreamMode::SHARE_DENYWRITE); + } + catch (const css::uno::Exception&) + { + } + + return xStream; +} + +std::vector calculateHash(std::unique_ptr& rStream) +{ + comphelper::Hash aHashEngine(comphelper::HashType::SHA1); + const sal_uInt32 nSize(rStream->remainingSize()); + std::vector aData(nSize); + aHashEngine.update(aData.data(), nSize); + return aHashEngine.finalize(); +} + +bool checkBitmap(Graphic& rGraphic) +{ + bool bResult = true; + + Bitmap aBitmap(rGraphic.GetBitmapEx().GetBitmap()); + { + Bitmap::ScopedReadAccess pReadAccess(aBitmap); + for (long y = 0; y < rGraphic.GetSizePixel().Height(); y++) + { + for (long x = 0; x < rGraphic.GetSizePixel().Width(); x++) + { + if (pReadAccess->HasPalette()) + { + sal_uInt32 nIndex = pReadAccess->GetPixelIndex(y, x); + Color aColor = pReadAccess->GetPaletteColor(nIndex); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + else + { + Color aColor = pReadAccess->GetPixel(y, x); + bResult &= (aColor == Color(0xff, 0x00, 0x00)); + } + } + } + } + + return bResult; +} + +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/data/"; + +void GraphicTest::testUnloadedGraphic() +{ + // make unloaded test graphic + Graphic aGraphic = makeUnloadedGraphic("png"); + Graphic aGraphic2 = aGraphic; + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic2.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic2.isAvailable()); + + // check GetSizePixel doesn't load graphic + aGraphic = makeUnloadedGraphic("png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetPrefSize doesn't load graphic + CPPUNIT_ASSERT_EQUAL(6000L, aGraphic.GetPrefSize().Width()); + CPPUNIT_ASSERT_EQUAL(5000L, aGraphic.GetPrefSize().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // check GetSizeBytes loads graphic + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + //check Type + aGraphic = makeUnloadedGraphic("png"); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); +} + +void GraphicTest::testUnloadedGraphicLoading() +{ + const OUString aFormats[] = { "png", "gif", "jpg" }; + + for (OUString const& sFormat : aFormats) + { + Graphic aGraphic = makeUnloadedGraphic(sFormat); + + // check available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT(aGraphic.GetSizeBytes() > 0); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + if (sFormat != "jpg") + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); + } +} + +void GraphicTest::testUnloadedGraphicWmf() +{ + // Create some in-memory WMF data, set its own preferred size to 99x99. + BitmapEx aBitmapEx = createBitmap(); + SvMemoryStream aStream; + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 nFilterFormat = rGraphicFilter.GetExportFormatNumberForShortName("wmf"); + Graphic aGraphic(aBitmapEx); + aGraphic.SetPrefSize(Size(99, 99)); + aGraphic.SetPrefMapMode(MapMode(MapUnit::Map100thMM)); + rGraphicFilter.ExportGraphic(aGraphic, "none", aStream, nFilterFormat); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Now lazy-load this WMF data, with a custom preferred size of 42x42. + Size aMtfSize100(42, 42); + aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 42x42 + // - Actual : 99x99 + // i.e. the custom preferred size was lost after lazy-load. + CPPUNIT_ASSERT_EQUAL(Size(42, 42), aGraphic.GetPrefSize()); +} + +void GraphicTest::testUnloadedGraphicAlpha() +{ + // make unloaded test graphic with alpha + Graphic aGraphic = makeUnloadedGraphic("png", true); + + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // make unloaded test graphic without alpha + aGraphic = makeUnloadedGraphic("png", false); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.IsTransparent()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); +} + +void GraphicTest::testUnloadedGraphicSizeUnit() +{ + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "inch-size.emf"; + Size aMtfSize100(42, 42); + SvFileStream aStream(aURL, StreamMode::READ); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream, 0, &aMtfSize100); + aGraphic.makeAvailable(); + + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 400x363 + // - Actual : 42x42 + // i.e. a mm100 size was used as a hint and the inch size was set for a non-matching unit. + CPPUNIT_ASSERT_EQUAL(Size(400, 363), aGraphic.GetPrefSize()); +} + +void GraphicTest::testSwapping() +{ + // Prepare Graphic from a PNG image first + Graphic aGraphic = makeUnloadedGraphic("png"); + + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + + BitmapChecksum aChecksumBeforeSwapping = aGraphic.GetChecksum(); + + CPPUNIT_ASSERT_EQUAL(sal_uInt32(319), aGraphic.GetGfxLink().GetDataSize()); + + // We loaded the Graphic and made it available + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + // Get the declared byte size of the graphic + sal_uLong rByteSize = aGraphic.GetSizeBytes(); + OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty()); + + // Swapping out + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Byte size doesn't change when we swapped out + CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes()); + + // Let's check the swap file + rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + { // Check the swap file content + std::unique_ptr xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(445), xStream->remainingSize()); + + std::vector aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("304f17d9c56e79b95f6c337dab88709d4f9b61f0"), + toHexString(aHash)); + } + + // Let's swap in + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + CPPUNIT_ASSERT_EQUAL(aChecksumBeforeSwapping, aGraphic.GetChecksum()); + + // File shouldn't be available anymore + CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + // Check the bitmap + CPPUNIT_ASSERT_EQUAL(120L, aGraphic.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(100L, aGraphic.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); + CPPUNIT_ASSERT_EQUAL(true, checkBitmap(aGraphic)); +} + +void GraphicTest::testSwappingVectorGraphic() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Load the vector graphic + CPPUNIT_ASSERT_EQUAL(true, bool(aGraphic.getVectorGraphicData())); + CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), + aGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(sal_uInt32(223), aGraphic.GetGfxLink().GetDataSize()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + + BitmapChecksum aBitmapChecksumBeforeSwapping = aGraphic.GetBitmapEx().GetChecksum(); + + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + // Get the declared byte size of the graphic + sal_uLong rByteSize = aGraphic.GetSizeBytes(); + CPPUNIT_ASSERT_EQUAL(sal_uLong(223), rByteSize); + OUString rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, rSwapFileURL.isEmpty()); + + // Swapping out + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->swapOut()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + + // Byte size doesn't change when we swapped out + // TODO: In case we don't trigger GetBitmapEx (above) the size is 0 + CPPUNIT_ASSERT_EQUAL(rByteSize, aGraphic.GetSizeBytes()); + + // Let's check the swap file + rSwapFileURL = aGraphic.ImplGetImpGraphic()->getSwapFileURL(); + CPPUNIT_ASSERT_EQUAL(true, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); + + { // Check the swap file content + std::unique_ptr xStream = createStream(rSwapFileURL); + CPPUNIT_ASSERT_EQUAL(true, bool(xStream)); + + // Check size of the stream + CPPUNIT_ASSERT_EQUAL(sal_uInt64(349), xStream->remainingSize()); + + std::vector aHash = calculateHash(xStream); + CPPUNIT_ASSERT_EQUAL(std::string("88b4c1c359e3cf7be005fbb46c93ffa6de9dcf4a"), + toHexString(aHash)); + } + + // Let's swap in + CPPUNIT_ASSERT_EQUAL(false, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.makeAvailable()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.isAvailable()); + CPPUNIT_ASSERT_EQUAL(false, aGraphic.ImplGetImpGraphic()->isSwappedOut()); + + CPPUNIT_ASSERT_EQUAL(aBitmapChecksumBeforeSwapping, aGraphic.GetBitmapEx().GetChecksum()); + + // File shouldn't be available anymore + CPPUNIT_ASSERT_EQUAL(false, comphelper::DirectoryHelper::fileExists(rSwapFileURL)); +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(GraphicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/ScanlineToolsTest.cxx b/vcl/qa/cppunit/ScanlineToolsTest.cxx new file mode 100644 index 000000000..bf053d3bc --- /dev/null +++ b/vcl/qa/cppunit/ScanlineToolsTest.cxx @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include + +namespace +{ +class ScanlineToolsTest : public CppUnit::TestFixture +{ + void ScanlineTransformer_32_ARGB(); + void ScanlineTransformer_24_BGR(); + void ScanlineTransformer_8bit_Palette(); + void ScanlineTransformer_4bit_Palette(); + void ScanlineTransformer_1bit_Palette(); + + CPPUNIT_TEST_SUITE(ScanlineToolsTest); + CPPUNIT_TEST(ScanlineTransformer_32_ARGB); + CPPUNIT_TEST(ScanlineTransformer_24_BGR); + CPPUNIT_TEST(ScanlineTransformer_8bit_Palette); + CPPUNIT_TEST(ScanlineTransformer_4bit_Palette); + CPPUNIT_TEST(ScanlineTransformer_1bit_Palette); + CPPUNIT_TEST_SUITE_END(); +}; + +void ScanlineToolsTest::ScanlineTransformer_32_ARGB() +{ + BitmapPalette aPalette; + std::unique_ptr pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(32, aPalette); + + std::vector aScanLine(5 * 4, 0); // 5 * 4 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector aExpectedBytes{ 0, 10, 250, 120, 50, 30, 230, 110, 100, 50, + 210, 100, 150, 70, 190, 90, 200, 90, 170, 80 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } +} + +void ScanlineToolsTest::ScanlineTransformer_24_BGR() +{ + BitmapPalette aPalette; + std::unique_ptr pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(24, aPalette); + + std::vector aScanLine(5 * 3, 0); // 5 * 3 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector aExpectedBytes{ 120, 250, 10, 110, 230, 30, 100, 210, + 50, 90, 190, 70, 80, 170, 90 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } +} + +void ScanlineToolsTest::ScanlineTransformer_8bit_Palette() +{ + std::vector aColors{ + Color(0, 10, 250, 120), Color(50, 30, 230, 110), Color(100, 50, 210, 100), + Color(150, 70, 190, 90), Color(200, 90, 170, 80), + }; + + BitmapPalette aPalette(256); + for (size_t i = 0; i < aColors.size(); ++i) + aPalette[i] = aColors[i]; + + std::unique_ptr pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(8, aPalette); + + std::vector aScanLine(5, 0); // 5 * 1 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector aExpectedBytes{ 0, 1, 2, 3, 4 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColors[i], aColor); + } +} + +void ScanlineToolsTest::ScanlineTransformer_4bit_Palette() +{ + std::vector aColors{ + Color(10, 250, 120), Color(30, 230, 110), Color(50, 210, 100), + Color(70, 190, 90), Color(90, 170, 80), Color(110, 150, 70), + }; + + BitmapPalette aPalette(16); + for (size_t i = 0; i < aColors.size(); ++i) + { + aPalette[i] = aColors[i]; + } + + std::unique_ptr pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(4, aPalette); + + std::vector aScanLine(3, 0); // 6 * 0.5 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector aExpectedBytes{ 0x01, 0x23, 0x45 }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColors[i], aColor); + } +} + +void ScanlineToolsTest::ScanlineTransformer_1bit_Palette() +{ + std::vector aColors{ + Color(10, 250, 120), Color(30, 230, 110), Color(50, 210, 100), Color(70, 190, 90), + Color(90, 170, 80), Color(110, 150, 70), Color(130, 130, 60), Color(150, 110, 50), + Color(170, 90, 40), Color(190, 70, 30), Color(210, 50, 20), Color(230, 30, 10), + Color(250, 10, 0), + }; + + BitmapPalette aPalette(2); + aPalette[0] = Color(10, 250, 120); + aPalette[1] = Color(110, 150, 70); + + std::unique_ptr pScanlineTransformer + = vcl::bitmap::getScanlineTransformer(1, aPalette); + + std::vector aScanLine(2, 0); // 13 * 1/8 BytesPerPixel + pScanlineTransformer->startLine(aScanLine.data()); + + for (Color const& aColor : aColors) + { + pScanlineTransformer->writePixel(aColor); + } + + std::vector aExpectedBytes{ + // We expect 3x index 0 and 10x index 1 => 000 111111111 + 0x1f, // 0001 1111 + 0xf8 // 1111 1000 + }; + + for (size_t i = 0; i < aScanLine.size(); ++i) + { + CPPUNIT_ASSERT_EQUAL(int(aExpectedBytes[i]), int(aScanLine[i])); + } + + pScanlineTransformer->startLine(aScanLine.data()); + + std::vector aColorsExpected{ + Color(10, 250, 120), Color(10, 250, 120), Color(10, 250, 120), Color(110, 150, 70), + Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), + Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), Color(110, 150, 70), + Color(110, 150, 70), + }; + + for (size_t i = 0; i < aColors.size(); ++i) + { + Color aColor = pScanlineTransformer->readPixel(); + CPPUNIT_ASSERT_EQUAL(aColorsExpected[i], aColor); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(ScanlineToolsTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/TypeSerializerTest.cxx b/vcl/qa/cppunit/TypeSerializerTest.cxx new file mode 100644 index 000000000..30966700a --- /dev/null +++ b/vcl/qa/cppunit/TypeSerializerTest.cxx @@ -0,0 +1,502 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if USE_TLS_NSS +#include +#endif + +namespace +{ +constexpr char DATA_DIRECTORY[] = "/vcl/qa/cppunit/data/"; + +std::vector calculateHash(SvStream& rStream) +{ + rStream.Seek(STREAM_SEEK_TO_BEGIN); + comphelper::Hash aHashEngine(comphelper::HashType::SHA1); + const sal_uInt32 nSize(rStream.remainingSize()); + std::vector aData(nSize); + aHashEngine.update(aData.data(), nSize); + return aHashEngine.finalize(); +} + +std::string toHexString(const std::vector& a) +{ + std::stringstream aStrm; + for (auto& i : a) + { + aStrm << std::setw(2) << std::setfill('0') << std::hex << static_cast(i); + } + + return aStrm.str(); +} + +class TypeSerializerTest : public CppUnit::TestFixture +{ +public: + ~TypeSerializerTest(); + +private: + void testGradient(); + void testGraphic_Vector(); + void testGraphic_Bitmap_NoGfxLink(); + void testGraphic_Animation(); + void testGraphic_GDIMetaFile(); + + CPPUNIT_TEST_SUITE(TypeSerializerTest); + CPPUNIT_TEST(testGradient); + CPPUNIT_TEST(testGraphic_Vector); + CPPUNIT_TEST(testGraphic_Bitmap_NoGfxLink); + CPPUNIT_TEST(testGraphic_Animation); + CPPUNIT_TEST(testGraphic_GDIMetaFile); + CPPUNIT_TEST_SUITE_END(); +}; + +TypeSerializerTest::~TypeSerializerTest() +{ +#if USE_TLS_NSS + NSS_Shutdown(); +#endif +} + +void TypeSerializerTest::testGradient() +{ + Gradient aGradient(GradientStyle::Radial, Color(0xFF, 0x00, 0x00), Color(0x00, 0xFF, 0x00)); + aGradient.SetAngle(900); + aGradient.SetBorder(5); + aGradient.SetOfsX(11); + aGradient.SetOfsY(12); + aGradient.SetStartIntensity(21); + aGradient.SetEndIntensity(22); + aGradient.SetSteps(30); + + SvMemoryStream aStream; + TypeSerializer aSerializer(aStream); + aSerializer.writeGradient(aGradient); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + Gradient aReadGradient; + aSerializer.readGradient(aReadGradient); + CPPUNIT_ASSERT_EQUAL(GradientStyle::Radial, aReadGradient.GetStyle()); + CPPUNIT_ASSERT_EQUAL(Color(0xFF, 0x00, 0x00), aReadGradient.GetStartColor()); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0x00), aReadGradient.GetEndColor()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(900), aReadGradient.GetAngle()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(5), aReadGradient.GetBorder()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(11), aReadGradient.GetOfsX()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(12), aReadGradient.GetOfsY()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(21), aReadGradient.GetStartIntensity()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(22), aReadGradient.GetEndIntensity()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(30), aReadGradient.GetSteps()); +} + +void TypeSerializerTest::testGraphic_Vector() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "SimpleExample.svg"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + aGraphic.makeAvailable(); + BitmapChecksum aChecksum = aGraphic.getVectorGraphicData()->GetChecksum(); + + // Test WriteGraphic - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(290), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("ee55ab6faa73b61b68bc3d5628d95f0d3c528e2a"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test WriteGraphic - Normal + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(233), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test TypeSerializer - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(290), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("ee55ab6faa73b61b68bc3d5628d95f0d3c528e2a"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } + + // Test TypeSerializer - Normal + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(233), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("c2bed2099ce617f1cc035701de5186f0d43e3064"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(createMagic('s', 'v', 'g', '0'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aChecksum, aNewGraphic.getVectorGraphicData()->GetChecksum()); + } +} + +void TypeSerializerTest::testGraphic_Bitmap_NoGfxLink() +{ + Bitmap aBitmap(Size(10, 10), 24); + aBitmap.Erase(COL_LIGHTGRAYBLUE); + BitmapEx aBitmapEx(aBitmap); + Graphic aGraphic(aBitmapEx); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(383), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da831418499146d51bf245fadf60b9111faa76c2"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(383), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da831418499146d51bf245fadf60b9111faa76c2"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); // Magic written with WriteDIBBitmapEx + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(aBitmapEx.GetChecksum(), aNewGraphic.GetBitmapExRef().GetChecksum()); + } +} + +void TypeSerializerTest::testGraphic_Animation() +{ + test::Directories aDirectories; + OUString aURL = aDirectories.getURLFromSrc(DATA_DIRECTORY) + "123_Numbers.gif"; + SvFileStream aStream(aURL, StreamMode::READ); + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(aStream); + aGraphic.makeAvailable(); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aGraphic.IsAnimated()); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(15167), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("69d0f80832a0aebcbda7ad43ecadf85e99fc1057"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test WriteGraphic - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(1582), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da3b9600340fa80a895f2107357e4ab65a9292eb"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(15167), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("69d0f80832a0aebcbda7ad43ecadf85e99fc1057"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt16 nType; + aMemoryStream.ReadUInt16(nType); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(0x4D42), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } + + // Test TypeSerializer - Native Format 5 + { + SvMemoryStream aMemoryStream; + aMemoryStream.SetVersion(SOFFICE_FILEFORMAT_50); + aMemoryStream.SetCompressMode(SvStreamCompressFlags::NATIVE); + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(1582), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("da3b9600340fa80a895f2107357e4ab65a9292eb"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + sal_uInt32 nType; + aMemoryStream.ReadUInt32(nType); + CPPUNIT_ASSERT_EQUAL(COMPAT_FORMAT('N', 'A', 'T', '5'), nType); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::Bitmap, aNewGraphic.GetType()); + CPPUNIT_ASSERT_EQUAL(true, aNewGraphic.IsAnimated()); + } +} + +void TypeSerializerTest::testGraphic_GDIMetaFile() +{ + GDIMetaFile aGDIMetaFile; + { + ScopedVclPtrInstance pVirtualDev; + pVirtualDev->SetConnectMetaFile(&aGDIMetaFile); + Size aVDSize(10, 10); + pVirtualDev->SetOutputSizePixel(aVDSize); + pVirtualDev->SetBackground(Wallpaper(COL_LIGHTRED)); + pVirtualDev->Erase(); + pVirtualDev->DrawPixel(Point(4, 4)); + } + Graphic aGraphic(aGDIMetaFile); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aGraphic.GetType()); + + // Test WriteGraphic + { + SvMemoryStream aMemoryStream; + WriteGraphic(aMemoryStream, aGraphic); + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(229), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("144c518e5149d61ab4bc34643df820372405d61d"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + char aIdCharArray[7] = { 0, 0, 0, 0, 0, 0, 0 }; + aMemoryStream.ReadBytes(aIdCharArray, 6); + OString sID(aIdCharArray); + CPPUNIT_ASSERT_EQUAL(OString("VCLMTF"), sID); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + ReadGraphic(aMemoryStream, aNewGraphic); + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aNewGraphic.GetType()); + } + + // Test TypeSerializer + { + SvMemoryStream aMemoryStream; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.writeGraphic(aGraphic); + } + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + + CPPUNIT_ASSERT_EQUAL(sal_uInt64(229), aMemoryStream.remainingSize()); + std::vector aHash = calculateHash(aMemoryStream); + CPPUNIT_ASSERT_EQUAL(std::string("144c518e5149d61ab4bc34643df820372405d61d"), + toHexString(aHash)); + + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + char aIdCharArray[7] = { 0, 0, 0, 0, 0, 0, 0 }; + aMemoryStream.ReadBytes(aIdCharArray, 6); + OString sID(aIdCharArray); + CPPUNIT_ASSERT_EQUAL(OString("VCLMTF"), sID); + + // Read it back + aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN); + Graphic aNewGraphic; + { + TypeSerializer aSerializer(aMemoryStream); + aSerializer.readGraphic(aNewGraphic); + } + CPPUNIT_ASSERT_EQUAL(GraphicType::GdiMetafile, aNewGraphic.GetType()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(TypeSerializerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeInfo.cxx b/vcl/qa/cppunit/app/test_IconThemeInfo.cxx new file mode 100644 index 000000000..d2e466d89 --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeInfo.cxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +#include +#include +#include + +using namespace vcl; + +class IconThemeInfoTest : public CppUnit::TestFixture +{ + void + UpperCaseDisplayNameIsReturnedForNonDefaultId(); + + void + ImagesZipIsNotValid(); + + void + ImagesColibreZipIsValid(); + + void + ThemeIdIsDetectedFromFileNameWithUnderscore(); + + void + ExceptionIsThrownWhenIdCannotBeDetermined1(); + + void + ExceptionIsThrownWhenIdCannotBeDetermined2(); + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeInfoTest); + CPPUNIT_TEST(UpperCaseDisplayNameIsReturnedForNonDefaultId); + CPPUNIT_TEST(ThemeIdIsDetectedFromFileNameWithUnderscore); + CPPUNIT_TEST(ImagesZipIsNotValid); + CPPUNIT_TEST(ImagesColibreZipIsValid); + CPPUNIT_TEST(ExceptionIsThrownWhenIdCannotBeDetermined1); + CPPUNIT_TEST(ExceptionIsThrownWhenIdCannotBeDetermined2); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +void +IconThemeInfoTest::UpperCaseDisplayNameIsReturnedForNonDefaultId() +{ + OUString const id("katze"); + OUString displayName = vcl::IconThemeInfo::ThemeIdToDisplayName(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("theme id is properly uppercased", OUString("Katze"), displayName); +} + +void +IconThemeInfoTest::ImagesZipIsNotValid() +{ + bool valid = vcl::IconThemeInfo::UrlCanBeParsed("file://images.zip"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("images.zip is not a valid theme name", false, valid); +} + +void +IconThemeInfoTest::ImagesColibreZipIsValid() +{ + OUString const id("file://images_colibre.zip"); + bool valid = vcl::IconThemeInfo::UrlCanBeParsed(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("images_colibre.zip is a valid theme name", true, valid); +} + +void +IconThemeInfoTest::ThemeIdIsDetectedFromFileNameWithUnderscore() +{ + OUString const fname("images_colibre.zip"); + OUString sname = vcl::IconThemeInfo::FileNameToThemeId(fname); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme id is returned for 'images_colibre.zip'", OUString("colibre"), sname); +} + +void +IconThemeInfoTest::ExceptionIsThrownWhenIdCannotBeDetermined1() +{ + bool thrown = false; + OUString const fname("images_colibre"); + try { + vcl::IconThemeInfo::FileNameToThemeId(fname); + } + catch (std::runtime_error&) { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception was thrown",true, thrown); +} + +void +IconThemeInfoTest::ExceptionIsThrownWhenIdCannotBeDetermined2() +{ + bool thrown = false; + OUString const fname("image_colibre.zip"); + try { + vcl::IconThemeInfo::FileNameToThemeId(fname); + } + catch (std::runtime_error&) { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception was thrown", true, thrown); +} + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeInfoTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeScanner.cxx b/vcl/qa/cppunit/app/test_IconThemeScanner.cxx new file mode 100644 index 000000000..f65e70bc6 --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeScanner.cxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include +#include +#include + +class IconThemeScannerTest : public CppUnit::TestFixture +{ + void + AddedThemeIsFoundById(); + + void + AddedThemeInfoIsReturned(); + + void + ExceptionIsThrownIfInvalidInfoIsRequested(); + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeScannerTest); + CPPUNIT_TEST(AddedThemeIsFoundById); + CPPUNIT_TEST(AddedThemeInfoIsReturned); + CPPUNIT_TEST(ExceptionIsThrownIfInvalidInfoIsRequested); + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +void +IconThemeScannerTest::AddedThemeIsFoundById() +{ + vcl::IconThemeScanner scanner; + scanner.AddIconThemeByPath("file:://images_katze.zip"); + OUString id = vcl::IconThemeInfo::FileNameToThemeId("images_katze.zip"); + bool found = scanner.IconThemeIsInstalled(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("icon theme could be added by url", true, found); +} + +void +IconThemeScannerTest::AddedThemeInfoIsReturned() +{ + vcl::IconThemeScanner scanner; + OUString theme("file:://images_katze.zip"); + scanner.AddIconThemeByPath(theme); + OUString id = vcl::IconThemeInfo::FileNameToThemeId("images_katze.zip"); + const vcl::IconThemeInfo& info = scanner.GetIconThemeInfo(id); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'katze' icon theme is found from id", theme, info.GetUrlToFile()); +} + +void +IconThemeScannerTest::ExceptionIsThrownIfInvalidInfoIsRequested() +{ + vcl::IconThemeScanner scanner; + scanner.AddIconThemeByPath("file:://images_katze.zip"); + bool thrown = false; + try + { + scanner.GetIconThemeInfo("hund"); + } + catch (const std::runtime_error&) + { + thrown = true; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception is thrown if invalid theme info is requested", true, thrown); +} + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeScannerTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/app/test_IconThemeSelector.cxx b/vcl/qa/cppunit/app/test_IconThemeSelector.cxx new file mode 100644 index 000000000..69f61c79e --- /dev/null +++ b/vcl/qa/cppunit/app/test_IconThemeSelector.cxx @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include +#include +#include +#include + +class IconThemeSelectorTest : public CppUnit::TestFixture +{ +#ifndef _WIN32 //default theme on Windows is Colibre independently from any desktop environment + void BreezeIsReturnedForKde5Desktop(); + void ElementaryIsReturnedForGnomeDesktop(); + void ThemeIsOverriddenByPreferredTheme(); + void ThemeIsOverriddenByHighContrastMode(); + void NotInstalledThemeDoesNotOverride(); + void InstalledThemeIsFound(); + void FirstThemeIsReturnedIfRequestedThemeIsNotFound(); + void FallbackThemeIsReturnedForEmptyInput(); + void DifferentPreferredThemesAreInequal(); + void DifferentHighContrastModesAreInequal(); + static std::vector GetFakeInstalledThemes(); +#endif + + // Adds code needed to register the test suite + CPPUNIT_TEST_SUITE(IconThemeSelectorTest); + +#ifndef _WIN32 + CPPUNIT_TEST(BreezeIsReturnedForKde5Desktop); + CPPUNIT_TEST(ElementaryIsReturnedForGnomeDesktop); + CPPUNIT_TEST(ThemeIsOverriddenByPreferredTheme); + CPPUNIT_TEST(ThemeIsOverriddenByHighContrastMode); + CPPUNIT_TEST(NotInstalledThemeDoesNotOverride); + CPPUNIT_TEST(InstalledThemeIsFound); + CPPUNIT_TEST(FirstThemeIsReturnedIfRequestedThemeIsNotFound); + CPPUNIT_TEST(FallbackThemeIsReturnedForEmptyInput); + CPPUNIT_TEST(DifferentPreferredThemesAreInequal); + CPPUNIT_TEST(DifferentHighContrastModesAreInequal); +#endif + + // End of test suite definition + CPPUNIT_TEST_SUITE_END(); +}; + +#ifndef _WIN32 + +/*static*/ std::vector +IconThemeSelectorTest::GetFakeInstalledThemes() +{ + std::vector r; + vcl::IconThemeInfo a; + a.mThemeId = "breeze"; + r.push_back(a); + a.mThemeId = "elementary"; + r.push_back(a); + a.mThemeId = "colibre"; + r.push_back(a); + a.mThemeId = "sifr"; + r.push_back(a); + return r; +} + +void +IconThemeSelectorTest::BreezeIsReturnedForKde5Desktop() +{ + std::vector themes = GetFakeInstalledThemes(); + vcl::IconThemeSelector s; + OUString r = s.SelectIconThemeForDesktopEnvironment(themes, "plasma5"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is returned for Plasma 5 desktop", OUString("breeze"), r); +} + +void +IconThemeSelectorTest::ElementaryIsReturnedForGnomeDesktop() +{ + std::vector themes = GetFakeInstalledThemes(); + vcl::IconThemeSelector s; + OUString r = s.SelectIconThemeForDesktopEnvironment(themes, "gnome"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'elementary' theme is returned for gnome desktop", OUString("elementary"), r); +} + +void +IconThemeSelectorTest::ThemeIsOverriddenByPreferredTheme() +{ + vcl::IconThemeSelector s; + OUString preferred("breeze"); + s.SetPreferredIconTheme(preferred, false); + std::vector themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconThemeForDesktopEnvironment(themes, "gnome"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'elementary' theme is overridden by breeze", preferred, selected); +} + +void +IconThemeSelectorTest::ThemeIsOverriddenByHighContrastMode() +{ + vcl::IconThemeSelector s; + s.SetUseHighContrastTheme(true); + std::vector themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "breeze"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is overridden by high contrast mode", + OUString("sifr"), selected); + s.SetUseHighContrastTheme(false); + selected = s.SelectIconTheme(themes, "breeze"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is no longer overridden by high contrast mode", + OUString("breeze"), selected); +} + +void +IconThemeSelectorTest::NotInstalledThemeDoesNotOverride() +{ + vcl::IconThemeSelector s; + s.SetPreferredIconTheme("breeze_foo", false); + std::vector themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme is not overridden by 'breeze_foo'", OUString("colibre"), selected); +} + +void +IconThemeSelectorTest::InstalledThemeIsFound() +{ + vcl::IconThemeSelector s; + std::vector themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'colibre' theme is found", OUString("colibre"), selected); +} + +void +IconThemeSelectorTest::FirstThemeIsReturnedIfRequestedThemeIsNotFound() +{ + vcl::IconThemeSelector s; + std::vector themes = GetFakeInstalledThemes(); + OUString selected = s.SelectIconTheme(themes, "breeze_foo"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("'breeze' theme is found", themes.front().GetThemeId(), selected); +} + +void +IconThemeSelectorTest::FallbackThemeIsReturnedForEmptyInput() +{ + vcl::IconThemeSelector s; + OUString selected = s.SelectIconTheme(std::vector(), "colibre"); + CPPUNIT_ASSERT_EQUAL_MESSAGE("fallback is returned for empty input", + OUString(vcl::IconThemeSelector::FALLBACK_ICON_THEME_ID), selected); +} + +void +IconThemeSelectorTest::DifferentHighContrastModesAreInequal() +{ + vcl::IconThemeSelector s1; + vcl::IconThemeSelector s2; + s1.SetUseHighContrastTheme(true); + s2.SetUseHighContrastTheme(false); + bool equal = (s1 == s2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Different high contrast modes are detected as inequal", false, equal); +} + +void +IconThemeSelectorTest::DifferentPreferredThemesAreInequal() +{ + vcl::IconThemeSelector s1; + vcl::IconThemeSelector s2; + s1.SetPreferredIconTheme("breeze", false); + s2.SetUseHighContrastTheme(true); + bool equal = (s1 == s2); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Different preferred themes are detected as inequal", false, equal); +} + +#endif + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(IconThemeSelectorTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmapcolor.cxx b/vcl/qa/cppunit/bitmapcolor.cxx new file mode 100644 index 000000000..eafa4d138 --- /dev/null +++ b/vcl/qa/cppunit/bitmapcolor.cxx @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// bootstrap stuff +#include + +#include + +namespace +{ +class BitmapColorTest : public test::BootstrapFixture +{ +public: + BitmapColorTest() + : BootstrapFixture(true, false) + { + } + + void defaultConstructor(); + void colorValueConstructor(); + void colorClassConstructor(); + void setValue(); + void invert(); + void getLuminance(); + + CPPUNIT_TEST_SUITE(BitmapColorTest); + CPPUNIT_TEST(defaultConstructor); + CPPUNIT_TEST(colorValueConstructor); + CPPUNIT_TEST(colorClassConstructor); + CPPUNIT_TEST(setValue); + CPPUNIT_TEST(invert); + CPPUNIT_TEST(getLuminance); + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapColorTest::defaultConstructor() +{ + BitmapColor aBmpColor; + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(0), aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), aBmpColor.GetAlpha()); +} + +void BitmapColorTest::colorValueConstructor() +{ + { + BitmapColor aBmpColor(0, 0, 0); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(0), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(128, 128, 128); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(128), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(128), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(128), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(255, 255, 255); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(255), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(255), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(255), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } +} + +void BitmapColorTest::colorClassConstructor() +{ + { + BitmapColor aBmpColor(Color(0, 0, 0)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(0), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(0), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(Color(127, 127, 127)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(127), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(127), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(127), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } + + { + BitmapColor aBmpColor(Color(255, 255, 255)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(255), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(255), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(255), + aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(0), + aBmpColor.GetAlpha()); + } + + // Transparency / Alpha + { + BitmapColor aBmpColor(Color(255, 128, 64, 0)); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Red wrong", static_cast(128), aBmpColor.GetRed()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Green wrong", static_cast(64), + aBmpColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Blue wrong", static_cast(0), aBmpColor.GetBlue()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Alpha wrong", static_cast(255), + aBmpColor.GetAlpha()); + } +} + +void BitmapColorTest::setValue() +{ + BitmapColor aBmpColor; + + aBmpColor.SetRed(127); + CPPUNIT_ASSERT_EQUAL(static_cast(127), aBmpColor.GetRed()); + + aBmpColor.SetGreen(127); + CPPUNIT_ASSERT_EQUAL(static_cast(127), aBmpColor.GetGreen()); + + aBmpColor.SetBlue(127); + CPPUNIT_ASSERT_EQUAL(static_cast(127), aBmpColor.GetBlue()); +} + +void BitmapColorTest::invert() +{ + BitmapColor aBmpColor(255, 255, 255); + BitmapColor aInvertedColor(aBmpColor); + aInvertedColor.Invert(); + + CPPUNIT_ASSERT_EQUAL(static_cast(0), aInvertedColor.GetRed()); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aInvertedColor.GetGreen()); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aInvertedColor.GetBlue()); +} + +void BitmapColorTest::getLuminance() +{ + { + BitmapColor aBmpColor(COL_BLACK); + CPPUNIT_ASSERT_EQUAL(static_cast(0), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_BLUE); + CPPUNIT_ASSERT_EQUAL(static_cast(14), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_GREEN); + CPPUNIT_ASSERT_EQUAL(static_cast(75), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_CYAN); + CPPUNIT_ASSERT_EQUAL(static_cast(90), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_RED); + CPPUNIT_ASSERT_EQUAL(static_cast(38), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_MAGENTA); + CPPUNIT_ASSERT_EQUAL(static_cast(52), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_BROWN); + CPPUNIT_ASSERT_EQUAL(static_cast(113), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_GRAY); + CPPUNIT_ASSERT_EQUAL(static_cast(128), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTGRAY); + CPPUNIT_ASSERT_EQUAL(static_cast(192), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTBLUE); + CPPUNIT_ASSERT_EQUAL(static_cast(28), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTGREEN); + CPPUNIT_ASSERT_EQUAL(static_cast(150), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTCYAN); + CPPUNIT_ASSERT_EQUAL(static_cast(179), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTRED); + CPPUNIT_ASSERT_EQUAL(static_cast(75), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_LIGHTMAGENTA); + CPPUNIT_ASSERT_EQUAL(static_cast(104), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_YELLOW); + CPPUNIT_ASSERT_EQUAL(static_cast(226), aBmpColor.GetLuminance()); + } + + { + BitmapColor aBmpColor(COL_WHITE); + CPPUNIT_ASSERT_EQUAL(static_cast(255), aBmpColor.GetLuminance()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapColorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx new file mode 100644 index 000000000..73e3baab9 --- /dev/null +++ b/vcl/qa/cppunit/bitmaprender/BitmapRenderTest.cxx @@ -0,0 +1,269 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +static OUString const gaDataUrl = "/vcl/qa/cppunit/bitmaprender/data/"; + +class BitmapRenderTest : public test::BootstrapFixture +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + +public: + BitmapRenderTest() + : BootstrapFixture(true, false) + { + } + + void testTdf104141(); + void testTdf113918(); + void testDrawAlphaBitmapEx(); + void testAlphaVirtualDevice(); + void testTdf116888(); + + CPPUNIT_TEST_SUITE(BitmapRenderTest); + CPPUNIT_TEST(testTdf104141); + CPPUNIT_TEST(testTdf113918); + CPPUNIT_TEST(testDrawAlphaBitmapEx); + CPPUNIT_TEST(testAlphaVirtualDevice); + CPPUNIT_TEST(testTdf116888); + + CPPUNIT_TEST_SUITE_END(); +}; + +void BitmapRenderTest::testTdf104141() +{ + ScopedVclPtrInstance pVDev; + pVDev->SetOutputSizePixel(Size(400, 400)); + pVDev->SetBackground(Wallpaper(COL_GREEN)); + pVDev->Erase(); + + // Load animated GIF and draw it on green background + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf104141.gif")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + pVDev->DrawBitmapEx(Point(20, 20), aBitmap); + + // Check drawing results: ensure that it contains transparent + // (greenish) pixels + const Color aColor = pVDev->GetPixel(Point(21, 21)); + CPPUNIT_ASSERT(aColor.GetGreen() > 10 * aColor.GetRed() + && aColor.GetGreen() > 10 * aColor.GetBlue()); +} + +void BitmapRenderTest::testTdf113918() +{ + ScopedVclPtrInstance pVDev; + pVDev->SetOutputSizePixel(Size(2480, 3508)); + pVDev->SetBackground(Wallpaper(COL_GREEN)); + pVDev->Erase(); + + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf113918.png")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + pVDev->DrawBitmapEx(Point(0, 0), aBitmap); + + // Ensure that image is drawn with white background color from palette + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(21, 21))); + + // Ensure that image is drawn with gray text color from palette + const Color aColor = pVDev->GetPixel(Point(1298, 1368)); + CPPUNIT_ASSERT(aColor.GetGreen() == aColor.GetRed() && aColor.GetGreen() == aColor.GetBlue()); + CPPUNIT_ASSERT(aColor.GetGreen() > 100); +} + +void BitmapRenderTest::testDrawAlphaBitmapEx() +{ + ScopedVclPtrInstance pVDev; + pVDev->SetOutputSizePixel(Size(8, 8)); + pVDev->SetBackground(Wallpaper(COL_WHITE)); + pVDev->Erase(); + + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(0, 0))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(1, 1))); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(2, 2))); + + SvFileStream aFileStream(getFullUrl("ImageRGBA.png"), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + // Check backend capabilities, if the backend support 32-bit bitmap + auto pBackendCapabilities = ImplGetSVData()->mpDefInst->GetBackendCapabilities(); + if (pBackendCapabilities->mbSupportsBitmap32) + { + CPPUNIT_ASSERT_EQUAL(sal_uInt16(32), aBitmapEx.GetBitmap().GetBitCount()); + } + else + { + CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmapEx.GetBitmap().GetBitCount()); + CPPUNIT_ASSERT_EQUAL(true, aBitmapEx.IsAlpha()); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), aBitmapEx.GetAlpha().GetBitCount()); + } + + // Check the bitmap has pixels we expect + CPPUNIT_ASSERT_EQUAL(Color(0xFF, 0x00, 0x00, 0x00), aBitmapEx.GetPixelColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0x00), aBitmapEx.GetPixelColor(1, 1)); + CPPUNIT_ASSERT_EQUAL(Color(0x7F, 0x00, 0xFF, 0x00), aBitmapEx.GetPixelColor(2, 2)); + + pVDev->DrawBitmapEx(Point(), aBitmapEx); + + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0xFF), pVDev->GetPixel(Point(0, 0))); + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0xFF, 0x00), pVDev->GetPixel(Point(1, 1))); + +// sometimes on Windows we get rounding error in blending so let's ignore this on Windows for now. +#if !defined(_WIN32) + CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x7F, 0xFF, 0x7F), pVDev->GetPixel(Point(2, 2))); +#endif +} + +#ifdef _WIN32 + +namespace +{ +int deltaColor(BitmapColor aColor1, BitmapColor aColor2) +{ + int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed()); + int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen()); + int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue()); + + return std::max(std::max(deltaR, deltaG), deltaB); +} +} + +#endif + +void BitmapRenderTest::testAlphaVirtualDevice() +{ + // Create an alpha virtual device + ScopedVclPtr pAlphaVirtualDevice(VclPtr::Create( + *Application::GetDefaultDevice(), DeviceFormat::DEFAULT, DeviceFormat::DEFAULT)); + + // Set it up + pAlphaVirtualDevice->SetOutputSizePixel(Size(4, 4)); + pAlphaVirtualDevice->SetBackground(Wallpaper(COL_TRANSPARENT)); + pAlphaVirtualDevice->Erase(); + + // Get a BitmapEx from the VirDev -> Colors should have alpha + BitmapEx aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + Color aColor = aBitmap.GetPixelColor(1, 1); + CPPUNIT_ASSERT_EQUAL(Color(0xffffffff), aColor); + + // Draw an opaque pixel to the VirDev + pAlphaVirtualDevice->DrawPixel(Point(1, 1), Color(0x0022ff55)); + + aColor = pAlphaVirtualDevice->GetPixel(Point(1, 1)); + // Read back the opaque pixel +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x0022ff55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x0022ff55), aColor); +#endif + + // Read back the BitmapEx and check the opaque pixel + aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + + aColor = aBitmap.GetPixelColor(1, 1); +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x0022ff55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x0022ff55), aColor); +#endif + + // Draw an semi-transparent pixel + pAlphaVirtualDevice->DrawPixel(Point(0, 0), Color(0x44, 0x22, 0xff, 0x55)); + + aColor = pAlphaVirtualDevice->GetPixel(Point(0, 0)); + // Read back the semi-transparent pixel +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x4422FF55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x4422FF55), aColor); +#endif + + // Read back the BitmapEx and check the semi-transparent pixel + aBitmap = pAlphaVirtualDevice->GetBitmapEx(Point(), Size(4, 4)); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL(long(4), aBitmap.GetSizePixel().Height()); + + aColor = aBitmap.GetPixelColor(0, 0); +#if defined _WIN32 + CPPUNIT_ASSERT_LESS(6, deltaColor(Color(0x4422FF55), aColor)); +#else + CPPUNIT_ASSERT_EQUAL(Color(0x4422FF55), aColor); +#endif +} + +void BitmapRenderTest::testTdf116888() +{ + // The image is a 8bit image with a non-grayscale palette. In OpenGL mode + // pdf export of the image was broken, because OpenGLSalBitmap::ReadTexture() + // didn't handle 8bit non-grayscale and moreover OpenGLSalBitmap::AcquireBuffer() + // didn't properly release mpUserBuffer after ReadTexture() failure. + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + const OUString aURL(getFullUrl("tdf116888.gif")); + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + CPPUNIT_ASSERT(!aBitmap.IsEmpty()); + aBitmap.Scale(0.8, 0.8); // This scaling discards mpUserData, + Bitmap::ScopedReadAccess pAccess(aBitmap); // forcing ReadTexture() here. + // Check that there is mpUserBuffer content. + CPPUNIT_ASSERT(pAccess); + const ScanlineFormat eFormat = pAccess->GetScanlineFormat(); + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, eFormat); + CPPUNIT_ASSERT(!aBitmap.HasGreyPaletteAny()); + // HACK: Some rendering backends change white to #FEFEFE while scaling for some reason. + // That is pretty much white too in practice, so adjust for that. + BitmapColor white(COL_WHITE); + if (pAccess->GetColor(0, 0) == Color(0xfe, 0xfe, 0xfe)) + white = Color(0xfe, 0xfe, 0xfe); + // Check that the image contents are also valid. + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(0, pAccess->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(white, pAccess->GetColor(pAccess->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + pAccess->GetColor(pAccess->Height() - 1, pAccess->Width() - 1)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(BitmapRenderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png b/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png new file mode 100644 index 000000000..7a8399293 Binary files /dev/null and b/vcl/qa/cppunit/bitmaprender/data/ImageRGBA.png differ diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif new file mode 100644 index 000000000..d6390fdaa Binary files /dev/null and b/vcl/qa/cppunit/bitmaprender/data/tdf104141.gif differ diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf113918.png b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png new file mode 100644 index 000000000..dd49897d9 Binary files /dev/null and b/vcl/qa/cppunit/bitmaprender/data/tdf113918.png differ diff --git a/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif new file mode 100644 index 000000000..295310949 Binary files /dev/null and b/vcl/qa/cppunit/bitmaprender/data/tdf116888.gif differ diff --git a/vcl/qa/cppunit/blocklistparsertest.cxx b/vcl/qa/cppunit/blocklistparsertest.cxx new file mode 100644 index 000000000..d62568de6 --- /dev/null +++ b/vcl/qa/cppunit/blocklistparsertest.cxx @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include + +#include + +#include + +using namespace DriverBlocklist; + +namespace +{ + +class BlocklistParserTest : public test::BootstrapFixtureBase +{ + void testParse(); + void testEvaluate(); + + CPPUNIT_TEST_SUITE(BlocklistParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testEvaluate); + CPPUNIT_TEST_SUITE_END(); +}; + +void BlocklistParserTest::testParse() +{ + std::vector aDriveInfos; + + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_parse.xml", + aDriveInfos, VersionType::OpenGL); + aBlocklistParser.parse(); + + size_t const n = aDriveInfos.size(); + CPPUNIT_ASSERT_EQUAL(static_cast(16), n); + + size_t i = 0; + + for (bool bIsWhitelisted : {true, false}) + { + DriverInfo& aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); // "all" + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_LESS_THAN, aDriveInfo.meComparisonOp); + CPPUNIT_ASSERT_EQUAL(OpenGLVersion(10,20,30,40), aDriveInfo.mnDriverVersion); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorNVIDIA), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorMicrosoft), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(OUString("0xcafe"), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_NOT_EQUAL, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_EXCLUSIVE, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_BETWEEN_INCLUSIVE_START, aDriveInfo.meComparisonOp); + + aDriveInfo = aDriveInfos[i++]; + CPPUNIT_ASSERT_EQUAL(bIsWhitelisted, aDriveInfo.mbWhitelisted); + CPPUNIT_ASSERT_EQUAL(GetVendorId(VendorAll), aDriveInfo.maAdapterVendor); + CPPUNIT_ASSERT_EQUAL(VersionComparisonOp::DRIVER_COMPARISON_IGNORED, aDriveInfo.meComparisonOp); + } +} + +void BlocklistParserTest::testEvaluate() +{ + std::vector aDriveInfos; + + Parser aBlocklistParser(m_directories.getURLFromSrc("vcl/qa/cppunit/") + "test_blocklist_evaluate.xml", + aDriveInfos, VersionType::OpenGL); + aBlocklistParser.parse(); + + OUString vendorAMD = GetVendorId(VendorAMD); + OUString vendorNVIDIA = GetVendorId(VendorNVIDIA); + OUString vendorIntel = GetVendorId(VendorIntel); + OUString vendorMicrosoft = GetVendorId(VendorMicrosoft); + + // Check OS + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_8)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorNVIDIA, "all", DRIVER_OS_WINDOWS_10)); + + // Check generic OS + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_LINUX)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_OSX_10_7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.50", vendorMicrosoft, "all", DRIVER_OS_OSX_10_8)); + + // Check Vendors + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorMicrosoft, "all", DRIVER_OS_WINDOWS_10)); + + // Check Versions + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.39", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.40", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + CPPUNIT_ASSERT_EQUAL(false, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "10.20.30.41", vendorAMD, "all", DRIVER_OS_WINDOWS_7)); + + // Check + CPPUNIT_ASSERT_EQUAL(true, FindBlocklistedDeviceInList( + aDriveInfos, VersionType::OpenGL, "9.17.10.4229", vendorIntel, "all", DRIVER_OS_WINDOWS_7)); + + +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(BlocklistParserTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/builder/demo.ui b/vcl/qa/cppunit/builder/demo.ui new file mode 100644 index 000000000..d5784b79f --- /dev/null +++ b/vcl/qa/cppunit/builder/demo.ui @@ -0,0 +1,1960 @@ + + + + + + + + + + + + [None] + + + Normal + + + + + + + + + + + 1 + + + 2 + + + 3 + + + 4 + + + 5 + + + 6 + + + 7 + + + 8 + + + 9 + + + 10 + + + 1 - 10 + + + + + False + 5 + dialog + + + + + + False + vertical + 2 + + + False + end + + + gtk-cancel + True + True + True + True + + + False + True + 0 + + + + + gtk-ok + True + True + True + True + + + False + True + 1 + + + + + False + True + end + 0 + + + + + True + True + + + True + False + vertical + + + True + False + 4 + 2 + True + True + + + True + False + cell 1.1 + + + 0 + 0 + + + + + True + False + cell 3.3 + 1 + + + 2 + 2 + + + + + True + False + A label that spans three rows + + + 0 + 1 + 3 + + + + + + + + + + + + + + + + + True + True + 0 + + + + + True + False + + + True + True + True + + + False + True + 0 + + + + + True + False + + + True + True + 1 + + + + + False + True + 1 + + + + + True + False + + + EXPAND + True + True + True + A tooltip example + + + True + True + 0 + + + + + FILL + True + True + True + + + False + True + 1 + + + + + False + True + 2 + + + + + True + False + + + button + True + True + True + + + False + True + 0 + + + + + radiobutton + True + True + False + True + 0 + True + True + + + False + True + 1 + + + + + checkbutton + True + True + False + True + 0 + True + + + False + True + 2 + + + + + False + True + 3 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + vertical + 6 + True + + + True + False + left + 0 + + + False + True + 0 + + + + + True + False + right + 1 + + + False + True + 1 + + + + + True + False + center + + + False + True + 2 + + + + + True + True + True + an edit control + + + False + True + 3 + + + + + + + + + True + False + Frame Label + + + + + False + True + 4 + + + + + + + True + False + page 1 + + + False + + + + + True + False + vertical + 10 + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 5 + True + + + True + False + _Number of title pages + True + NF_PAGE_COUNT + 0 + + + 0 + 2 + + + + + True + False + Place title pages at + 0 + + + 0 + 3 + + + + + True + False + pages + 0 + + + 2 + 2 + 2 + + + + + True + True + True + + + 1 + 2 + + + + + True + False + True + True + + + + + + 2 + 4 + 2 + + + + + Converting existing pages to title pages + True + True + False + True + 0 + True + RB_INSERT_NEW_PAGES + + + 0 + 0 + 4 + + + + + Insert new title pages + True + True + False + True + 0 + True + RB_USE_EXISTING_PAGES + + + 0 + 1 + 4 + + + + + Document Start + True + True + False + True + 0 + True + RB_PAGE_START + + + 1 + 3 + 3 + + + + + Page + True + True + False + True + 0 + True + RB_DOCUMENT_START + + + + + + 1 + 4 + + + + + + + + + + + + True + False + Make Title Pages + + + + + True + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + vertical + True + + + Reset Page Numbering after title pages + True + True + False + True + 0 + True + + + False + True + 0 + + + + + True + False + + + True + False + Page number + + + + + + False + True + 0 + + + + + True + False + True + True + + + + + + False + True + 1 + + + + + False + True + 1 + + + + + Set Page Number for first title page + True + True + False + True + 0 + True + + + False + True + 2 + + + + + True + False + + + True + False + Page number + + + + + + False + True + 0 + + + + + True + False + True + True + + + + + + False + True + 1 + + + + + False + True + 3 + + + + + + + + + True + False + Page Numbering + + + + + True + True + 1 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + + + True + False + + + True + True + 0 + + + + + Edit... + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Edit Page Properties + + + + + False + True + 2 + + + + + 1 + + + + + True + False + page 2 + + + 1 + False + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + vertical + + + Line break + True + True + False + True + 0 + True + True + + + False + True + 0 + + + + + Column break + True + True + False + True + 0 + True + 2 + + + False + True + 1 + + + + + Page break + True + True + False + True + 0 + True + 2 + + + False + True + 2 + + + + + True + False + Style + 5 + 0 + + + False + True + 3 + + + + + True + False + liststore1 + + + False + True + 4 + + + + + Change page number + True + True + False + True + 0 + True + + + + + + False + True + 5 + + + + + True + False + + + True + True + + + + + + False + True + 0 + + + + + + + + False + True + 6 + + + + + + + + + True + False + Type + + + + + 2 + + + + + True + False + page 3 + + + 2 + False + + + + + True + False + True + + + True + False + 0 + none + + + True + False + 12 + + + True + False + vertical + + + Optimal + True + True + False + True + 0 + True + True + + + False + True + 0 + + + + + Fit width and height + True + True + False + True + 0 + True + 15 + + + False + True + 1 + + + + + Fit width + True + True + False + True + 0 + True + 15 + + + False + True + 2 + + + + + 100% + True + True + False + True + 0 + True + 15 + + + False + True + 3 + + + + + True + False + + + Variable + True + True + False + True + 0 + True + 15 + + + + + + False + True + 0 + + + + + True + True + + + + + + False + True + 1 + + + + + False + True + 4 + + + + + + + + + True + False + Zoom factor + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + vertical + + + Automatic + True + True + False + True + 0 + True + True + + + False + True + 0 + + + + + Single page + True + True + False + True + 0 + True + 22 + + + False + True + 1 + + + + + True + False + + + Columns + True + True + False + True + 0 + True + 22 + + + + + + False + True + 0 + + + + + True + True + + + + + + False + True + 1 + + + + + False + True + 2 + + + + + True + False + 10 + + + Book mode + True + True + False + True + 0 + True + + + + + False + True + 3 + + + + + + + + + True + False + View layout + + + + + False + True + 1 + + + + + 3 + + + + + True + False + page 4 + + + 3 + False + + + + + True + False + 10 + 10 + + + True + False + 0 + none + + + True + False + 12 + + + True + True + liststore2 + False + 0 + + + + + + + + + + True + False + Level + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 10 + + + True + False + vertical + + + True + False + 10 + + + True + False + Paragraph Style + combobox2 + 0 + + + 0 + 0 + 2 + + + + + True + False + + + 0 + 1 + 2 + + + + + True + False + Number + combobox3 + 0 + + + 0 + 2 + + + + + True + False + Character Style + combobox4 + 0 + + + 0 + 3 + + + + + True + False + Show sublevels + spinbutton2 + 0 + + + 0 + 4 + + + + + True + False + Separator + 0 + + + 0 + 5 + 2 + + + + + True + False + + + 1 + 2 + + + + + True + False + + + 1 + 3 + + + + + True + True + + + 1 + 4 + + + + + True + True + + + 1 + 6 + + + + + True + True + + + 1 + 7 + + + + + True + True + + + 1 + 8 + + + + + True + False + 20 + + + True + False + Before + entry2 + 0 + + + + + 0 + 6 + + + + + True + False + 20 + + + True + False + After + entry3 + 0 + + + + + 0 + 7 + + + + + True + False + Start at + spinbutton3 + 0 + + + 0 + 8 + + + + + False + True + 0 + + + + + False + True + 0 + + + + + 150 + 200 + True + False + + + True + True + 1 + + + + + + + + + True + False + Numbering + + + + + True + True + 1 + + + + + 4 + + + + + True + False + page 5 + + + 4 + False + + + + + True + False + 10 + 10 + + + True + False + 0 + none + + + True + False + 12 + + + True + True + liststore2 + False + 0 + + + + + + + + + + True + False + Level + + + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 12 + + + True + False + 10 + 10 + + + True + False + Numbering followed by + combobox5 + 0 + + + 0 + 0 + + + + + True + False + Numbering Alignment + combobox6 + 0 + + + 0 + 2 + + + + + True + False + Aligned at + spinbutton6 + 0 + + + 0 + 3 + + + + + True + False + Indent at + spinbutton4 + 0 + + + 0 + 4 + + + + + True + False + + + 1 + 2 + + + + + True + True + + + 1 + 4 + + + + + True + False + at + spinbutton5 + 1 + + + 0 + 1 + + + + + True + True + + + 1 + 1 + + + + + True + True + + + 1 + 3 + + + + + True + False + + + 1 + 0 + + + + + 300 + 150 + True + False + + + 0 + 5 + + + + + Default + True + True + True + end + + + 1 + 5 + + + + + + + + + True + False + Position and spacing + + + + + True + True + 1 + + + + + 5 + + + + + True + False + page 6 + + + 5 + False + + + + + True + True + True + + + True + False + 200 + 400 + + + True + False + label + + + 0 + 0 + + + + + True + False + label + + + 0 + 1 + + + + + True + False + label + + + 0 + 2 + + + + + True + False + label + + + 1 + 0 + + + + + True + False + label + + + 1 + 1 + + + + + True + False + label + + + 1 + 2 + + + + + + + True + False + Details + + + + + 6 + + + + + True + False + page 7 + + + 6 + False + + + + + True + True + 1 + + + + + + cancel + ok + + + diff --git a/vcl/qa/cppunit/canvasbitmaptest.cxx b/vcl/qa/cppunit/canvasbitmaptest.cxx new file mode 100644 index 000000000..511874a0c --- /dev/null +++ b/vcl/qa/cppunit/canvasbitmaptest.cxx @@ -0,0 +1,773 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// bootstrap stuff +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace vcl::unotools; + +namespace com::sun::star::rendering +{ + +static bool operator==( const RGBColor& rLHS, const ARGBColor& rRHS ) +{ + return rLHS.Red == rRHS.Red && rLHS.Green == rRHS.Green && rLHS.Blue == rRHS.Blue; +} + +} + +namespace +{ + +class CanvasBitmapTest : public test::BootstrapFixture +{ +public: + CanvasBitmapTest() : BootstrapFixture(true, false) {} + + void runTest(); + + CPPUNIT_TEST_SUITE(CanvasBitmapTest); + CPPUNIT_TEST(runTest); + CPPUNIT_TEST_SUITE_END(); +}; + +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& xBmp, + const char* msg, + int nOriginalDepth ) +{ + SAL_INFO("vcl", "Testing " << msg << ", with depth " << nOriginalDepth); + + BitmapEx aContainedBmpEx( xBmp->getBitmapEx() ); + Bitmap aContainedBmp( aContainedBmpEx.GetBitmap() ); + int nDepth = nOriginalDepth; + int extraBpp = 0; + + { + Bitmap::ScopedReadAccess pAcc( aContainedBmp ); + nDepth = pAcc->GetBitCount(); + if( pAcc->GetScanlineFormat() == ScanlineFormat::N32BitTcMask ) + extraBpp = 8; // the format has 8 unused bits + } + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Original bitmap size not (200,200)", + Size(200,200), aContainedBmp.GetSizePixel()); + + CPPUNIT_ASSERT_MESSAGE( "Original bitmap size via API not (200,200)", + xBmp->getSize().Width == 200 && xBmp->getSize().Height == 200); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "alpha state mismatch", + aContainedBmpEx.IsTransparent(), bool(xBmp->hasAlpha())); + + CPPUNIT_ASSERT_MESSAGE( "getScaledBitmap() failed", + xBmp->getScaledBitmap( geometry::RealSize2D(500,500), false ).is()); + + rendering::IntegerBitmapLayout aLayout; + uno::Sequence aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,1,1)); + + const sal_Int32 nExpectedBitsPerPixel( + (aContainedBmpEx.IsTransparent() ? std::max(8,nDepth)+8 : nDepth) + extraBpp); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanlines not 1", + static_cast(1), aLayout.ScanLines); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanline bytes mismatch", + static_cast((nExpectedBitsPerPixel+7)/8), aLayout.ScanLineBytes); + CPPUNIT_ASSERT_MESSAGE( "# scanline stride mismatch", + aLayout.ScanLineStride == (nExpectedBitsPerPixel+7)/8 || + aLayout.ScanLineStride == -(nExpectedBitsPerPixel+7)/8); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# plane stride not 0", + static_cast(0), aLayout.PlaneStride); + + CPPUNIT_ASSERT_MESSAGE( "Color space not there", + aLayout.ColorSpace.is()); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Palette existence does not conform to bitmap", + (nDepth <= 8), aLayout.Palette.is()); + + uno::Sequence aPixelData2 = xBmp->getPixel( aLayout, geometry::IntegerPoint2D(0,0) ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "getData and getPixel did not return same amount of data", + aPixelData.getLength(), aPixelData2.getLength()); + + aPixelData = xBmp->getData(aLayout, geometry::IntegerRectangle2D(0,0,200,1)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanlines not 1 for getPixel", + static_cast(1), aLayout.ScanLines); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "# scanline bytes mismatch for getPixel", + static_cast((200*nExpectedBitsPerPixel+7)/8), aLayout.ScanLineBytes); + CPPUNIT_ASSERT_MESSAGE( "# scanline stride mismatch for getPixel", + aLayout.ScanLineStride == (200*nExpectedBitsPerPixel+7)/8 || + aLayout.ScanLineStride == -(200*nExpectedBitsPerPixel+7)/8); + + 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 aRes = std::mismatch( pRGBStart, pRGBEnd, pARGBStart ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "argb and rgb colors are not equal", + pRGBEnd, aRes.first); + + CPPUNIT_ASSERT_MESSAGE( "rgb colors are not within [0,1] range", + std::none_of(pRGBStart,pRGBEnd,&rangeCheck)); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Red, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Green, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "First pixel is not white", 1.0, pRGBStart[0].Blue, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "Second pixel is not opaque", 1.0, pARGBStart[1].Alpha, 1E-12); + if( aContainedBmpEx.IsTransparent() ) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE( "First pixel is not fully transparent", + 0.0, pARGBStart[0].Alpha); + } + + CPPUNIT_ASSERT_MESSAGE( "Second pixel is not black", + pRGBStart[1].Red == 0.0 && pRGBStart[1].Green == 0.0 && pRGBStart[1].Blue == 0.0); + + if( nOriginalDepth > 8 ) + { + const Color aCol(COL_GREEN); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (red component)", + vcl::unotools::toDoubleColor(aCol.GetRed()), pRGBStart[5].Red); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (green component)", + vcl::unotools::toDoubleColor(aCol.GetGreen()), pRGBStart[5].Green); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Sixth pixel is not green (blue component)", + vcl::unotools::toDoubleColor(aCol.GetBlue()), pRGBStart[5].Blue); + } + else if( nDepth <= 8 ) + { + uno::Reference xPal = xBmp->getPalette(); + CPPUNIT_ASSERT_MESSAGE( "8bit or less: missing palette", + xPal.is()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Palette incorrect entry count", + static_cast(1 << nOriginalDepth), xPal->getNumberOfEntries()); + uno::Sequence aIndex; + CPPUNIT_ASSERT_MESSAGE( "Palette is not read-only", + !xPal->setIndex(aIndex,true,0)); + CPPUNIT_ASSERT_MESSAGE( "Palette entry 0 is not opaque", + xPal->getIndex(aIndex,0)); + CPPUNIT_ASSERT_MESSAGE( "Palette has no valid color space", + xPal->getColorSpace().is()); + } + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Red, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Green, 1E-12); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "150th pixel is not white", 1.0, pRGBStart[150].Blue, 1E-12); + + if( nOriginalDepth <= 8 ) + return; + + uno::Sequence aARGBColor(1); + uno::Sequence aRGBColor(1); + uno::Sequence 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) ); + CPPUNIT_ASSERT_MESSAGE( "Green pixel from bitmap mismatch with manually converted green pixel", + bool(aPixel3 == aPixel4)); + + if( !aContainedBmpEx.IsTransparent() ) + { + aPixel3 = xBmp->convertIntegerFromRGB( aRGBColor ); + CPPUNIT_ASSERT_MESSAGE( "Green pixel from bitmap mismatch with manually RGB-converted green pixel", + bool(aPixel3 == aPixel4)); + } + +} + +class TestBitmap : public cppu::WeakImplHelper< rendering::XIntegerReadOnlyBitmap, + rendering::XBitmapPalette, + rendering::XIntegerBitmapColorSpace > +{ +private: + geometry::IntegerSize2D maSize; + uno::Sequence maComponentTags; + uno::Sequence maComponentBitCounts; + rendering::IntegerBitmapLayout maLayout; + const sal_Int32 mnBitsPerPixel; + + // XBitmap + virtual geometry::IntegerSize2D SAL_CALL getSize() override { return maSize; } + virtual sal_Bool SAL_CALL hasAlpha( ) override { return mnBitsPerPixel != 8; } + virtual uno::Reference< rendering::XBitmap > SAL_CALL getScaledBitmap( const geometry::RealSize2D&, + sal_Bool ) override { return this; } + + // XIntegerReadOnlyBitmap + virtual uno::Sequence< ::sal_Int8 > SAL_CALL getData( rendering::IntegerBitmapLayout& bitmapLayout, + const geometry::IntegerRectangle2D& rect ) override + { + CPPUNIT_ASSERT_MESSAGE( "X1 out of bounds", rect.X1 >= 0 ); + CPPUNIT_ASSERT_MESSAGE( "Y1 out of bounds", rect.Y1 >= 0 ); + CPPUNIT_ASSERT_MESSAGE( "X2 out of bounds", rect.X2 <= maSize.Width ); + CPPUNIT_ASSERT_MESSAGE( "Y2 out of bounds", rect.Y2 <= maSize.Height ); + + 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 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 SAL_CALL getPixel( rendering::IntegerBitmapLayout&, + const geometry::IntegerPoint2D& ) override + { + CPPUNIT_ASSERT_MESSAGE("getPixel: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + /// @throws uno::RuntimeException + uno::Reference< rendering::XBitmapPalette > getPalette( ) + { + uno::Reference< XBitmapPalette > aRet; + if( mnBitsPerPixel == 8 ) + aRet.set(this); + return aRet; + } + + virtual rendering::IntegerBitmapLayout SAL_CALL getMemoryLayout( ) override + { + 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() override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette getNumberOfEntries interface call without handing out palette", + getPalette().is() ); + + return 255; + } + + virtual sal_Bool SAL_CALL getIndex( uno::Sequence< double >& entry, + ::sal_Int32 nIndex ) override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette getIndex interface call without handing out palette", + getPalette().is() ); + CPPUNIT_ASSERT_MESSAGE( "getIndex: index out of range", + nIndex >= 0 && nIndex < 256 ); + entry = colorToStdColorSpaceSequence( + Color(sal_uInt8(nIndex), + sal_uInt8(nIndex), + sal_uInt8(nIndex)) ); + + return true; // no palette transparency here. + } + + virtual sal_Bool SAL_CALL setIndex( const uno::Sequence< double >&, + sal_Bool, + ::sal_Int32 nIndex ) override + { + CPPUNIT_ASSERT_MESSAGE( "Got palette setIndex interface call without handing out palette", + getPalette().is()); + CPPUNIT_ASSERT_MESSAGE( "setIndex: index out of range", + nIndex >= 0 && nIndex < 256); + return false; + } + + struct PaletteColorSpaceHolder: public rtl::StaticWithInit, + PaletteColorSpaceHolder> + { + uno::Reference operator()() + { + return vcl::unotools::createStandardColorSpace(); + } + }; + + virtual uno::Reference< rendering::XColorSpace > SAL_CALL getColorSpace( ) override + { + // this is the method from XBitmapPalette. Return palette color + // space here + return PaletteColorSpaceHolder::get(); + } + + // XIntegerBitmapColorSpace + virtual ::sal_Int8 SAL_CALL getType( ) override + { + return rendering::ColorSpaceType::RGB; + } + + virtual uno::Sequence< sal_Int8 > SAL_CALL getComponentTags( ) override + { + return maComponentTags; + } + + virtual ::sal_Int8 SAL_CALL getRenderingIntent( ) override + { + return rendering::RenderingIntent::PERCEPTUAL; + } + + virtual uno::Sequence< beans::PropertyValue > SAL_CALL getProperties() override + { + CPPUNIT_ASSERT_MESSAGE("getProperties: method not implemented", false ); + return uno::Sequence< ::beans::PropertyValue >(); + } + + virtual uno::Sequence< double > SAL_CALL convertColorSpace( const uno::Sequence< double >&, + const uno::Reference< rendering::XColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertColorSpace: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertToRGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToRGB: method not implemented", false); + return uno::Sequence< rendering::RGBColor >(); + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToARGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToARGB: method not implemented", false); + return uno::Sequence< rendering::ARGBColor >(); + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertToPARGB( const uno::Sequence< double >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToPARGB: method not implemented", false); + return uno::Sequence< rendering::ARGBColor >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromRGB( const uno::Sequence< rendering::RGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromRGB: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromARGB: this method is not expected to be called!", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< double > SAL_CALL convertFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromPARGB: this method is not expected to be called!", false); + return uno::Sequence< double >(); + } + + virtual ::sal_Int32 SAL_CALL getBitsPerPixel( ) override + { + return mnBitsPerPixel; + } + + virtual uno::Sequence< ::sal_Int32 > SAL_CALL getComponentBitCounts( ) override + { + return maComponentBitCounts; + } + + virtual ::sal_Int8 SAL_CALL getEndianness( ) override + { + return util::Endianness::LITTLE; + } + + virtual uno::Sequence< double > SAL_CALL convertFromIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& , + const uno::Reference< rendering::XColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertFromIntegerColorSpace: method not implemented", false); + return uno::Sequence< double >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertToIntegerColorSpace( const uno::Sequence< ::sal_Int8 >& , + const uno::Reference< rendering::XIntegerBitmapColorSpace >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertToIntegerColorSpace: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< rendering::RGBColor > SAL_CALL convertIntegerToRGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override + { + const uno::Sequence< rendering::ARGBColor > aTemp( convertIntegerToARGB(deviceColor) ); + uno::Sequence< rendering::RGBColor > aRes( aTemp.getLength() ); + std::transform(aTemp.begin(), aTemp.end(), aRes.begin(), + [](const rendering::ARGBColor& rColor) { + return rendering::RGBColor(rColor.Red, + rColor.Green, + rColor.Blue); + }); + + return aRes; + } + + virtual uno::Sequence< rendering::ARGBColor > SAL_CALL convertIntegerToARGB( const uno::Sequence< ::sal_Int8 >& deviceColor ) override + { + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("number of channels no multiple of pixel element count", + 0, static_cast(nLen%nBytesPerPixel)); + + uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel ); + + if( getPalette().is() ) + { + std::transform(deviceColor.begin(), deviceColor.end(), aRes.begin(), + [](sal_Int8 nIn) { + auto fColor = vcl::unotools::toDoubleColor(nIn); + return rendering::ARGBColor(1.0, fColor, fColor, fColor); + }); + } + else + { + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i SAL_CALL convertIntegerToPARGB( + const uno::Sequence< ::sal_Int8 >& deviceColor) override + { + const std::size_t nLen( deviceColor.getLength() ); + const sal_Int32 nBytesPerPixel(mnBitsPerPixel == 8 ? 1 : 4); + CPPUNIT_ASSERT_EQUAL_MESSAGE("number of channels no multiple of pixel element count", + 0, static_cast(nLen%nBytesPerPixel)); + + uno::Sequence< rendering::ARGBColor > aRes( nLen / nBytesPerPixel ); + + if( getPalette().is() ) + { + std::transform(deviceColor.begin(), deviceColor.end(), aRes.begin(), + [](sal_Int8 nIn) { + auto fColor = vcl::unotools::toDoubleColor(nIn); + return rendering::ARGBColor(1.0, fColor, fColor, fColor); + }); + } + else + { + rendering::ARGBColor* pOut( aRes.getArray() ); + for( std::size_t i=0; i SAL_CALL convertIntegerFromRGB( + const uno::Sequence< rendering::RGBColor >&) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromRGB: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromARGB: method not implemented", false); + return uno::Sequence< sal_Int8 >(); + } + + virtual uno::Sequence< ::sal_Int8 > SAL_CALL convertIntegerFromPARGB( const uno::Sequence< rendering::ARGBColor >& ) override + { + CPPUNIT_ASSERT_MESSAGE("convertIntegerFromPARGB: method not implemented", false); + 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 = false; + } +}; + +void CanvasBitmapTest::runTest() +{ + static const sal_Int8 lcl_depths[]={1,4,8,24}; + + // Testing VclCanvasBitmap wrapper + + for( size_t i=0; iHasPalette() ) + { + aBlack.SetIndex( sal::static_int_cast(pAcc->GetBestPaletteIndex(BitmapColor(0,0,0))) ); + aWhite.SetIndex( sal::static_int_cast(pAcc->GetBestPaletteIndex(BitmapColor(255,255,255))) ); + } + else + { + aBlack = COL_BLACK; + aWhite = COL_WHITE; + } + pAcc->SetFillColor(COL_GREEN); + pAcc->FillRect(tools::Rectangle(0,0,100,100)); + pAcc->SetPixel(0,0,aWhite); + pAcc->SetPixel(0,1,aBlack); + pAcc->SetPixel(0,2,aWhite); + } + } + + rtl::Reference xBmp( new VclCanvasBitmap(BitmapEx(aBitmap)) ); + + checkCanvasBitmap( xBmp, "single bitmap", nDepth ); + + Bitmap aMask(Size(200,200),1); + aMask.Erase(COL_WHITE); + { + BitmapScopedWriteAccess pAcc(aMask); + if( pAcc.get() ) + { + pAcc->SetFillColor(COL_BLACK); + pAcc->FillRect(tools::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(tools::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); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap is transparent", + !aBmp.IsTransparent()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have size (10,10)", + Size(10,10), aBmp.GetSizePixel()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have bitcount of 8", + static_cast(8), aBmp.GetBitCount()); + { + Bitmap aBitmap = aBmp.GetBitmap(); + BitmapReadAccess* pBmpAcc = aBitmap.AcquireReadAccess(); + + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid BitmapReadAccess", + pBmpAcc ); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect content", + BitmapColor(0), pBmpAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect content", + BitmapColor(2), pBmpAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) incorrect content", + BitmapColor(9), pBmpAcc->GetPixel(2,9)); + + Bitmap::ReleaseAccess(pBmpAcc); + } + + xTestBmp.set( new TestBitmap( geometry::IntegerSize2D(10,10), false )); + + aBmp = vcl::unotools::bitmapExFromXBitmap(xTestBmp); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap is not transparent", + aBmp.IsTransparent()); + CPPUNIT_ASSERT_MESSAGE( "Palette bitmap has no alpha", + aBmp.IsAlpha()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap does not have size (10,10)", + Size(10,10), aBmp.GetSizePixel()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bitmap has bitcount of 24", + static_cast(24), aBmp.GetBitCount()); + { + Bitmap aBitmap = aBmp.GetBitmap(); + BitmapReadAccess* pBmpAcc = aBitmap.AcquireReadAccess(); + BitmapReadAccess* pAlphaAcc = aBmp.GetAlpha().AcquireReadAccess(); + + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid BitmapReadAccess", + pBmpAcc); + CPPUNIT_ASSERT_MESSAGE( "Bitmap has invalid alpha BitmapReadAccess", + pAlphaAcc); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect content", + BitmapColor(0,1,0), pBmpAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(0,0) incorrect alpha content", + BitmapColor(255), pAlphaAcc->GetPixel(0,0)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect content", + BitmapColor(0,3,2), pBmpAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(2,2) incorrect alpha content", + BitmapColor(253), pAlphaAcc->GetPixel(2,2)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) incorrect content", + BitmapColor(0,3,9), pBmpAcc->GetPixel(2,9)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("(9,2) correct alpha content", + BitmapColor(253), pAlphaAcc->GetPixel(2,9)); + + aBmp.GetAlpha().ReleaseAccess(pAlphaAcc); + Bitmap::ReleaseAccess(pBmpAcc); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(CanvasBitmapTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx new file mode 100644 index 000000000..85a5b3991 --- /dev/null +++ b/vcl/qa/cppunit/complextext.cxx @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +#if HAVE_MORE_FONTS +// must be declared before inclusion of test/bootstrapfixture.hxx +static std::ostream& operator<<(std::ostream& rStream, const std::vector& rVec); +#endif +#include + +#include +#include +// workaround MSVC2015 issue with std::unique_ptr +#include +#include + +#if HAVE_MORE_FONTS +static std::ostream& operator<<(std::ostream& rStream, const std::vector& rVec) +{ + rStream << "{ "; + for (size_t i = 0; i < rVec.size() - 1; i++) + rStream << rVec[i] << ", "; + rStream << rVec.back(); + rStream << " }"; + return rStream; +} +#endif + +class VclComplexTextTest : public test::BootstrapFixture +{ +public: + VclComplexTextTest() : BootstrapFixture(true, false) {} + + /// Play with font measuring etc. + void testArabic(); + void testKashida(); + void testTdf95650(); // Windows-only issue + + CPPUNIT_TEST_SUITE(VclComplexTextTest); + CPPUNIT_TEST(testArabic); + CPPUNIT_TEST(testKashida); + CPPUNIT_TEST(testTdf95650); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclComplexTextTest::testArabic() +{ +#if HAVE_MORE_FONTS + const unsigned char pOneTwoThreeUTF8[] = { + 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90, + 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8, + 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9, + 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7, + 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00 + }; + OUString aOneTwoThree( reinterpret_cast(pOneTwoThreeUTF8), + SAL_N_ELEMENTS( pOneTwoThreeUTF8 ) - 1, + RTL_TEXTENCODING_UTF8 ); + ScopedVclPtrInstance pWin(static_cast(nullptr)); + CPPUNIT_ASSERT( pWin ); + + vcl::Font aFont("DejaVu Sans", "Book", Size(0, 12)); + + OutputDevice *pOutDev = pWin.get(); + pOutDev->SetFont( aFont ); + + // absolute character widths AKA text array. + std::vector aRefCharWidths {6, 9, 16, 16, 22, 22, 26, 29, 32, 32, + 36, 40, 49, 53, 56, 63, 63, 66, 72, 72}; + std::vector aCharWidths(aOneTwoThree.getLength(), 0); + long nTextWidth = pOutDev->GetTextArray(aOneTwoThree, aCharWidths.data()); + + CPPUNIT_ASSERT_EQUAL(aRefCharWidths, aCharWidths); + // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73 + CPPUNIT_ASSERT_EQUAL(72L, nTextWidth); + CPPUNIT_ASSERT_EQUAL(nTextWidth, aCharWidths.back()); + + // text advance width and line height + CPPUNIT_ASSERT_EQUAL(72L, pOutDev->GetTextWidth(aOneTwoThree)); + CPPUNIT_ASSERT_EQUAL(14L, pOutDev->GetTextHeight()); + + // exact bounding rectangle, not essentially the same as text width/height + tools::Rectangle aBoundRect, aTestRect( 0, 1, 71, 15 ); + pOutDev->GetTextBoundRect(aBoundRect, aOneTwoThree); + CPPUNIT_ASSERT_EQUAL(aTestRect, aBoundRect); + +#if 0 + // FIXME: This seems to be wishful thinking, GetTextRect() does not take + // rotation into account. + + // normal orientation + tools::Rectangle aInput; + tools::Rectangle aRect = pOutDev->GetTextRect( aInput, aOneTwoThree ); + + // now rotate 270 degrees + vcl::Font aRotated( aFont ); + aRotated.SetOrientation( 2700 ); + pOutDev->SetFont( aRotated ); + tools::Rectangle aRectRot = pOutDev->GetTextRect( aInput, aOneTwoThree ); + + // Check that we did do the rotation... + fprintf( stderr, "%ld %ld %ld %ld\n", + aRect.GetWidth(), aRect.GetHeight(), + aRectRot.GetWidth(), aRectRot.GetHeight() ); + CPPUNIT_ASSERT( aRectRot.GetWidth() == aRect.GetHeight() ); + CPPUNIT_ASSERT( aRectRot.GetHeight() == aRect.GetWidth() ); +#endif +#endif +} + +void VclComplexTextTest::testKashida() +{ +#if HAVE_MORE_FONTS + // Cache the glyph list of some Arabic text. + ScopedVclPtrInstance pOutputDevice; + auto aText + = OUString::fromUtf8(u8"ﻊﻨﺻﺭ ﺎﻠﻓﻮﺴﻓﻭﺭ ﻊﻨﺻﺭ ﻒﻟﺰﻳ ﺺﻠﺑ. ﺖﺘﻛﻮﻧ ﺎﻟﺩﻭﺭﺓ ﺎﻟﺭﺎﺒﻋﺓ ﻢﻧ ١٥ ﻊﻨﺻﺭïº."); + std::unique_ptr pLayout = pOutputDevice->ImplLayout( + aText, 0, aText.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly); + const SalLayoutGlyphs* pGlyphs = pLayout->GetGlyphs(); + if (!pGlyphs) + // Failed in some non-interesting ways. + return; + SalLayoutGlyphs aGlyphs = *pGlyphs; + + // Now lay it out using the cached glyph list. + ImplLayoutArgs aLayoutArgs(aText, 0, aText.getLength(), SalLayoutFlags::NONE, + pOutputDevice->GetFont().GetLanguageTag(), nullptr); + pLayout = pOutputDevice->GetGraphics()->GetTextLayout(0); + CPPUNIT_ASSERT(pLayout->LayoutText(aLayoutArgs, &aGlyphs)); + + // Without the accompanying fix in place, this test would have failed with 'assertion failed'. + // The kashida justification flag was lost when going via the glyph cache. + CPPUNIT_ASSERT(aLayoutArgs.mnFlags & SalLayoutFlags::KashidaJustification); +#endif +} + +void VclComplexTextTest::testTdf95650() +{ + const sal_Unicode pTxt[] = { + 0x0131, 0x0302, 0x0504, 0x4E44, 0x3031, 0x3030, 0x3531, 0x2D30, + 0x3037, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E, 0x072E, 0x100A, + 0x0D11, 0x1312, 0x0105, 0x020A, 0x0512, 0x1403, 0x030C, 0x1528, + 0x2931, 0x632E, 0x7074, 0x0D20, 0x0E0A, 0x100A, 0xF00D, 0x0D20, + 0x030A, 0x0C0B, 0x20E0, 0x0A0D + }; + OUString aTxt(pTxt, SAL_N_ELEMENTS(pTxt) - 1); + ScopedVclPtrInstance pWin(static_cast(nullptr)); + CPPUNIT_ASSERT(pWin); + + OutputDevice *pOutDev = pWin.get(); + // Check that the following executes without failing assertion + pOutDev->ImplLayout(aTxt, 9, 1, Point(), 0, nullptr, SalLayoutFlags::BiDiRtl); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclComplexTextTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/data/123_Numbers.gif b/vcl/qa/cppunit/data/123_Numbers.gif new file mode 100644 index 000000000..2e47e28cb Binary files /dev/null and b/vcl/qa/cppunit/data/123_Numbers.gif differ diff --git a/vcl/qa/cppunit/data/Exif1.jpg b/vcl/qa/cppunit/data/Exif1.jpg new file mode 100644 index 000000000..a81425e75 Binary files /dev/null and b/vcl/qa/cppunit/data/Exif1.jpg differ diff --git a/vcl/qa/cppunit/data/Exif1_090CW.jpg b/vcl/qa/cppunit/data/Exif1_090CW.jpg new file mode 100644 index 000000000..bb8a81a16 Binary files /dev/null and b/vcl/qa/cppunit/data/Exif1_090CW.jpg differ diff --git a/vcl/qa/cppunit/data/Exif1_180.jpg b/vcl/qa/cppunit/data/Exif1_180.jpg new file mode 100644 index 000000000..b18b70f13 Binary files /dev/null and b/vcl/qa/cppunit/data/Exif1_180.jpg differ diff --git a/vcl/qa/cppunit/data/Exif1_270CW.jpg b/vcl/qa/cppunit/data/Exif1_270CW.jpg new file mode 100644 index 000000000..f10764114 Binary files /dev/null and b/vcl/qa/cppunit/data/Exif1_270CW.jpg differ diff --git a/vcl/qa/cppunit/data/SimpleExample.svg b/vcl/qa/cppunit/data/SimpleExample.svg new file mode 100644 index 000000000..6890b5456 --- /dev/null +++ b/vcl/qa/cppunit/data/SimpleExample.svg @@ -0,0 +1,4 @@ + + + + diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.bmp b/vcl/qa/cppunit/data/TypeDetectionExample.bmp new file mode 100644 index 000000000..5197e42a7 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.bmp differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.eps b/vcl/qa/cppunit/data/TypeDetectionExample.eps new file mode 100644 index 000000000..7f0db47bc --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.eps @@ -0,0 +1,82 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: cairo 1.16.0 (https://cairographics.org) +%%CreationDate: Sat May 2 14:29:27 2020 +%%Pages: 1 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%BoundingBox: 0 1 7 8 +%%EndComments +%%BeginProlog +50 dict begin +/q { gsave } bind def +/Q { grestore } bind def +/cm { 6 array astore concat } bind def +/w { setlinewidth } bind def +/J { setlinecap } bind def +/j { setlinejoin } bind def +/M { setmiterlimit } bind def +/d { setdash } bind def +/m { moveto } bind def +/l { lineto } bind def +/c { curveto } bind def +/h { closepath } bind def +/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto + 0 exch rlineto 0 rlineto closepath } bind def +/S { stroke } bind def +/f { fill } bind def +/f* { eofill } bind def +/n { newpath } bind def +/W { clip } bind def +/W* { eoclip } bind def +/BT { } bind def +/ET { } bind def +/BDC { mark 3 1 roll /BDC pdfmark } bind def +/EMC { mark /EMC pdfmark } bind def +/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def +/Tj { show currentpoint cairo_store_point } bind def +/TJ { + { + dup + type /stringtype eq + { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse + } forall + currentpoint cairo_store_point +} bind def +/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore + cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def +/Tf { pop /cairo_font exch def /cairo_font_matrix where + { pop cairo_selectfont } if } bind def +/Td { matrix translate cairo_font_matrix matrix concatmatrix dup + /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point + /cairo_font where { pop cairo_selectfont } if } bind def +/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def + cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def +/g { setgray } bind def +/rg { setrgbcolor } bind def +/d1 { setcachedevice } bind def +/cairo_data_source { + CairoDataIndex CairoData length lt + { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def } + { () } ifelse +} def +/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def +/cairo_image { image cairo_flush_ascii85_file } def +/cairo_imagemask { imagemask cairo_flush_ascii85_file } def +%%EndProlog +%%BeginSetup +%%EndSetup +%%Page: 1 1 +%%BeginPageSetup +%%PageBoundingBox: 0 1 7 8 +%%EndPageSetup +q 0 1 7 7 rectclip +1 0 0 -1 0 8 cm q +0.956863 0.831373 0.266667 rg +3.75 0.75 m 5.41 0.75 6.75 2.09 6.75 3.75 c 6.75 5.41 5.41 6.75 3.75 6.75 + c 2.09 6.75 0.75 5.41 0.75 3.75 c 0.75 2.09 2.09 0.75 3.75 0.75 c h +3.75 0.75 m f +Q Q +showpage +%%Trailer +end +%%EOF diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.gif b/vcl/qa/cppunit/data/TypeDetectionExample.gif new file mode 100644 index 000000000..b33eb4f90 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.gif differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.jpg b/vcl/qa/cppunit/data/TypeDetectionExample.jpg new file mode 100644 index 000000000..b8436eaa1 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.jpg differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.met b/vcl/qa/cppunit/data/TypeDetectionExample.met new file mode 100644 index 000000000..7635e841f Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.met differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pcx b/vcl/qa/cppunit/data/TypeDetectionExample.pcx new file mode 100644 index 000000000..639323455 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.pcx differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.pdf b/vcl/qa/cppunit/data/TypeDetectionExample.pdf new file mode 100644 index 000000000..b68bff5e1 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.pdf differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.png b/vcl/qa/cppunit/data/TypeDetectionExample.png new file mode 100644 index 000000000..f73f5fd74 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.png differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.psd b/vcl/qa/cppunit/data/TypeDetectionExample.psd new file mode 100644 index 000000000..8282b14fd Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.psd differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.svg b/vcl/qa/cppunit/data/TypeDetectionExample.svg new file mode 100644 index 000000000..e23e44c23 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.svg @@ -0,0 +1,4 @@ + + + + diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.svgz b/vcl/qa/cppunit/data/TypeDetectionExample.svgz new file mode 100644 index 000000000..17c1bcc3c Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.svgz differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tga b/vcl/qa/cppunit/data/TypeDetectionExample.tga new file mode 100644 index 000000000..870c88b10 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.tga differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.tif b/vcl/qa/cppunit/data/TypeDetectionExample.tif new file mode 100644 index 000000000..dc74dc958 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.tif differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.wmf b/vcl/qa/cppunit/data/TypeDetectionExample.wmf new file mode 100644 index 000000000..7ed706928 Binary files /dev/null and b/vcl/qa/cppunit/data/TypeDetectionExample.wmf differ diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.xbm b/vcl/qa/cppunit/data/TypeDetectionExample.xbm new file mode 100644 index 000000000..b40d1a45e --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.xbm @@ -0,0 +1,5 @@ +#define sample_width 10 +#define sample_height 10 +static unsigned char sample_bits[] = { + 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, + 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00 }; diff --git a/vcl/qa/cppunit/data/TypeDetectionExample.xpm b/vcl/qa/cppunit/data/TypeDetectionExample.xpm new file mode 100644 index 000000000..7b9b94359 --- /dev/null +++ b/vcl/qa/cppunit/data/TypeDetectionExample.xpm @@ -0,0 +1,15 @@ +/* XPM */ +static char * sample_xpm[] = { +"10 10 2 1", +" c #FFFFFF", +". c #72D1C8", +" ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" ........ ", +" "}; diff --git a/vcl/qa/cppunit/data/inch-size.emf b/vcl/qa/cppunit/data/inch-size.emf new file mode 100644 index 000000000..ac5a1b805 Binary files /dev/null and b/vcl/qa/cppunit/data/inch-size.emf differ diff --git a/vcl/qa/cppunit/data/testBasicMorphology.png b/vcl/qa/cppunit/data/testBasicMorphology.png new file mode 100644 index 000000000..5db565779 Binary files /dev/null and b/vcl/qa/cppunit/data/testBasicMorphology.png differ diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png new file mode 100644 index 000000000..ba335bab3 Binary files /dev/null and b/vcl/qa/cppunit/data/testBasicMorphologyDilated1.png differ diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png new file mode 100644 index 000000000..3b10a949a Binary files /dev/null and b/vcl/qa/cppunit/data/testBasicMorphologyDilated1Eroded1.png differ diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png new file mode 100644 index 000000000..30d90757e Binary files /dev/null and b/vcl/qa/cppunit/data/testBasicMorphologyDilated2.png differ diff --git a/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png new file mode 100644 index 000000000..a506577da Binary files /dev/null and b/vcl/qa/cppunit/data/testBasicMorphologyDilated2Eroded1.png differ diff --git a/vcl/qa/cppunit/dndtest.cxx b/vcl/qa/cppunit/dndtest.cxx new file mode 100644 index 000000000..37629239b --- /dev/null +++ b/vcl/qa/cppunit/dndtest.cxx @@ -0,0 +1,311 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 MyWin : public WorkWindow +{ +public: + MyWin( vcl::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::WeakImplHelper < XDropTargetListener, XDragGestureListener, XDragSourceListener > +{ + vcl::Window * m_pWindow; + +public: + + explicit MyDragAndDropListener( vcl::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: + + explicit MyInfoBox( vcl::Window* pParent ); +}; + +class MyListBox : public ListBox +{ + +public: + + explicit MyListBox( vcl::Window* pParent ); +}; + +class StringTransferable : public ::cppu::WeakImplHelper< XTransferable > +{ + const OUString m_aData; + Sequence< DataFlavor > m_aFlavorList; + +public: + explicit StringTransferable( const OUString& rString ) : m_aData( rString ), m_aFlavorList( 1 ) + { + DataFlavor df; + + df.MimeType = "text/plain;charset=utf-16"; + df.DataType = cppu::UnoType::get(); + + 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 bool SAL_CALL isDataFlavorSupported( const DataFlavor& aFlavor ) throw(RuntimeException); +}; + +class VclDnDTest : public test::BootstrapFixture +{ +public: + VclDnDTest() : BootstrapFixture(true, false) {} + + /// Play with drag and drop + void testDnD(); + + CPPUNIT_TEST_SUITE(VclDnDTest); + CPPUNIT_TEST(testDnD); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclDnDTest::testDnD() +{ + MyWin aMainWin( NULL, WB_APP | WB_STDWORK ); + aMainWin.SetText( OUString( "Drag And Drop - Workbench" ) ); + aMainWin.Show(); + + // test the clipboard code + Reference< XClipboard > xClipboard = aMainWin.GetClipboard(); + CPPUNIT_ASSERT_MESSAGE("System clipboard not available", + xClipboard.is()); + + MyInfoBox aInfoBox( &aMainWin ); + aInfoBox.Execute(); + + MyListBox aListBox( &aMainWin ); + aListBox.setPosSizePixel( 10, 10, 100, 100 ); + aListBox.InsertEntry( OUString("TestItem")); + aListBox.Show(); +} + +MyWin::MyWin( vcl::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( 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) +{ + Reference< XDragSource > xDragSource( dge.DragSource, UNO_QUERY ); + xDragSource->startDrag( dge, -1, 0, 0, new StringTransferable( OUString("TestString") ), this ); +} + +void SAL_CALL MyDragAndDropListener::drop( const DropTargetDropEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->dropComplete( true ); +} + +void SAL_CALL MyDragAndDropListener::dragEnter( const DropTargetDragEnterEvent& dtdee ) throw(RuntimeException) +{ + dtdee.Context->acceptDrag( dtdee.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dragExit( const DropTargetEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragOver( const DropTargetDragEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->acceptDrag( dtde.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dropActionChanged( const DropTargetDragEvent& dtde ) throw(RuntimeException) +{ + dtde.Context->acceptDrag( dtde.DropAction ); +} + +void SAL_CALL MyDragAndDropListener::dragDropEnd( const DragSourceDropEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragEnter( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragExit( const DragSourceEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dragOver( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::dropActionChanged( const DragSourceDragEvent& ) throw(RuntimeException) +{ +} + +void SAL_CALL MyDragAndDropListener::disposing( const EventObject& ) throw(RuntimeException) +{ +} + +MyInfoBox::MyInfoBox( vcl::Window* pParent ) : InfoBox( pParent, + OUString("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( true ); + } + + Reference< XDragGestureRecognizer > xRecognizer = GetDragGestureRecognizer(); + if( xRecognizer.is() ) + xRecognizer->addDragGestureListener( Reference< XDragGestureListener > ( xListener, UNO_QUERY ) ); +}; + +MyListBox::MyListBox( vcl::Window* pParent ) : ListBox( pParent ) +{ + Reference< XDropTargetListener > xListener = new MyDragAndDropListener( this ); + + Reference< XDropTarget > xDropTarget = GetDropTarget(); + if( xDropTarget.is() ) + { + xDropTarget->addDropTargetListener( xListener ); + xDropTarget->setActive( 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; +} + +bool SAL_CALL StringTransferable::isDataFlavorSupported( const DataFlavor& ) + throw(RuntimeException) +{ + return true; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclDnDTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/errorhandler.cxx b/vcl/qa/cppunit/errorhandler.cxx new file mode 100644 index 000000000..21c672ac5 --- /dev/null +++ b/vcl/qa/cppunit/errorhandler.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +class ErrorHandlerTest; + +namespace { + +class MockErrorHandler : private ErrorHandler +{ + friend ErrorHandlerTest; + +protected: + virtual bool CreateString(const ErrorInfo *pErrInfo, OUString &rErrString) const override + { + if (pErrInfo->GetErrorCode().IsDynamic()) + rErrString = "Dynamic error"; + else + rErrString = "Non-dynamic error"; + + return true; + } +}; + +} + +class ErrorHandlerTest : public test::BootstrapFixture +{ +public: + ErrorHandlerTest() : BootstrapFixture(true, false) {} + + void testGetErrorString(); + + CPPUNIT_TEST_SUITE(ErrorHandlerTest); + CPPUNIT_TEST(testGetErrorString); + CPPUNIT_TEST_SUITE_END(); +}; + +void ErrorHandlerTest::testGetErrorString() +{ + MockErrorHandler aErrHdlr; + std::unique_ptr xErrorInfo; + OUString aErrStr; + + CPPUNIT_ASSERT_MESSAGE("GetErrorString(ERRCODE_ABORT, aErrStr) should return false", + !ErrorHandler::GetErrorString(ERRCODE_ABORT, aErrStr)); + // normally protected, but MockErrorHandler is a friend of this class + xErrorInfo = ErrorInfo::GetErrorInfo(ERRCODE_ABORT); + aErrHdlr.CreateString(xErrorInfo.get(), aErrStr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("error message should be non-dynamic", OUString("Non-dynamic error"), aErrStr); + + CPPUNIT_ASSERT_MESSAGE("GetErrorString(ERRCODE_NONE, aErrStr) should return false", + !ErrorHandler::GetErrorString(ERRCODE_NONE, aErrStr)); + xErrorInfo = ErrorInfo::GetErrorInfo(ERRCODE_NONE); + aErrHdlr.CreateString(xErrorInfo.get(), aErrStr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("error message should be non-dynamic", OUString("Non-dynamic error"), aErrStr); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ErrorHandlerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf new file mode 100644 index 000000000..73de3117b --- /dev/null +++ b/vcl/qa/cppunit/filter/ipdf/data/dict-array-dict.pdf @@ -0,0 +1,55 @@ +%PDF-1.7 +% ò¤ô +1 0 obj << + /Type /Catalog + /Pages 2 0 R +>> +endobj +2 0 obj << + /Type /Pages + /MediaBox [0 0 200 300] + /Count 1 + /Kids [3 0 R] +>> +endobj +3 0 obj << + /Type /Page + /Parent 2 0 R + /Contents 4 0 R + /Key[<>] +>> +endobj +4 0 obj << + /Length 188 +>> +stream +q +0 0 0 rg +0 290 10 10 re B* +10 150 50 30 re B* +0 0 1 rg +190 290 10 10 re B* +70 232 50 30 re B* +0 1 0 rg +190 0 10 10 re B* +130 150 50 30 re B* +1 0 0 rg +0 0 10 10 re B* +70 67 50 30 re B* +Q +endstream +endobj +xref +0 5 +0000000000 65535 f +0000000015 00000 n +0000000068 00000 n +0000000157 00000 n +0000000251 00000 n +trailer << + /Root 1 0 R + /Size 5 +>> +startxref +491 +%%EOF diff --git a/vcl/qa/cppunit/filter/ipdf/ipdf.cxx b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx new file mode 100644 index 000000000..0f94f3276 --- /dev/null +++ b/vcl/qa/cppunit/filter/ipdf/ipdf.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/filter/ipdf/data/"; +} + +/// Covers vcl/source/filter/ipdf/ fixes. +class VclFilterIpdfTest : public test::BootstrapFixture, public unotest::MacrosTest +{ +public: + void setUp() override; +}; + +void VclFilterIpdfTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); +} + +CPPUNIT_TEST_FIXTURE(VclFilterIpdfTest, testDictArrayDict) +{ + // Load a file that has markup like this: + // 3 0 obj << + // /Key[<>] + // >> + OUString aSourceURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "dict-array-dict.pdf"; + SvFileStream aFile(aSourceURL, StreamMode::READ); + vcl::filter::PDFDocument aDocument; + CPPUNIT_ASSERT(aDocument.Read(aFile)); + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT(!aPages.empty()); + vcl::filter::PDFObjectElement* pPage = aPages[0]; + auto pKey = dynamic_cast(pPage->Lookup("Key")); + + // Without the accompanying fix in place, this test would have failed, because the value of Key + // was a dictionary element, not an array element. + CPPUNIT_ASSERT(pKey); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/font.cxx b/vcl/qa/cppunit/font.cxx new file mode 100644 index 000000000..e99bf12a5 --- /dev/null +++ b/vcl/qa/cppunit/font.cxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +class VclFontTest : public test::BootstrapFixture +{ +public: + VclFontTest() : BootstrapFixture(true, false) {} + + void testName(); + void testWeight(); + void testWidthType(); + void testPitch(); + void testItalic(); + void testAlignment(); + void testQuality(); + void testSymbolFlagAndCharSet(); + + CPPUNIT_TEST_SUITE(VclFontTest); + CPPUNIT_TEST(testName); + CPPUNIT_TEST(testWeight); + CPPUNIT_TEST(testWidthType); + CPPUNIT_TEST(testPitch); + CPPUNIT_TEST(testItalic); + CPPUNIT_TEST(testAlignment); + CPPUNIT_TEST(testQuality); + CPPUNIT_TEST(testSymbolFlagAndCharSet); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontTest::testName() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_MESSAGE( "Family name should be empty", aFont.GetFamilyName().isEmpty()); + CPPUNIT_ASSERT_MESSAGE( "Style name should be empty", aFont.GetStyleName().isEmpty()); + aFont.SetFamilyName("Test family name"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Family name should not be empty", OUString("Test family name"), aFont.GetFamilyName()); + aFont.SetStyleName("Test style name"); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Style name should not be empty", OUString("Test style name"), aFont.GetStyleName()); +} + +void VclFontTest::testWeight() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Weight should be WEIGHT_DONTKNOW", FontWeight::WEIGHT_DONTKNOW, aFont.GetWeight()); + + aFont.SetWeight(FontWeight::WEIGHT_BLACK); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Weight should be WEIGHT_BLACK", FontWeight::WEIGHT_BLACK, aFont.GetWeight()); +} + +void VclFontTest::testWidthType() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font width should be WIDTH_DONTKNOW", FontWidth::WIDTH_DONTKNOW, aFont.GetWidthType()); + + aFont.SetWidthType(FontWidth::WIDTH_EXPANDED); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Font width should be EXPANDED", FontWidth::WIDTH_EXPANDED, aFont.GetWidthType()); +} + +void VclFontTest::testItalic() +{ + vcl::Font aFont; + + // shouldn't this be set to ITALIC_DONTKNOW? currently it defaults to ITALIC_NONE + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Italic should be ITALIC_NONE", FontItalic::ITALIC_NONE, aFont.GetItalic()); + + aFont.SetItalic(FontItalic::ITALIC_NORMAL); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Italic should be EXPANDED", FontItalic::ITALIC_NORMAL, aFont.GetItalic()); +} + + +void VclFontTest::testAlignment() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Text alignment should be ALIGN_TOP", TextAlign::ALIGN_TOP, aFont.GetAlignment()); + + aFont.SetAlignment(TextAlign::ALIGN_BASELINE); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Text alignment should be ALIGN_BASELINE", TextAlign::ALIGN_BASELINE, aFont.GetAlignment()); +} + + +void VclFontTest::testPitch() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Pitch should be PITCH_DONTKNOW", FontPitch::PITCH_DONTKNOW, aFont.GetPitch()); + + aFont.SetPitch(FontPitch::PITCH_FIXED); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Pitch should be PITCH_FIXED", FontPitch::PITCH_FIXED, aFont.GetPitch()); +} + +void VclFontTest::testQuality() +{ + vcl::Font aFont; + + CPPUNIT_ASSERT_EQUAL( int(0), aFont.GetQuality() ); + + aFont.SetQuality( 100 ); + CPPUNIT_ASSERT_EQUAL( int(100), aFont.GetQuality() ); + + aFont.IncreaseQualityBy( 50 ); + CPPUNIT_ASSERT_EQUAL( int(150), aFont.GetQuality() ); + + aFont.DecreaseQualityBy( 100 ); + CPPUNIT_ASSERT_EQUAL( int(50), aFont.GetQuality() ); +} + + +void VclFontTest::testSymbolFlagAndCharSet() +{ + // default constructor should set scalable flag to false + vcl::Font aFont; + + CPPUNIT_ASSERT_MESSAGE( "Should not be seen as a symbol font after default constructor called", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Character set should be RTL_TEXTENCODING_DONTKNOW after default constructor called", + RTL_TEXTENCODING_DONTKNOW, aFont.GetCharSet() ); + + aFont.SetSymbolFlag(true); + + CPPUNIT_ASSERT_MESSAGE( "Test 1: Symbol font flag should be on", aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 1: Character set should be RTL_TEXTENCODING_SYMBOL", + RTL_TEXTENCODING_SYMBOL, aFont.GetCharSet() ); + + aFont.SetSymbolFlag(false); + + CPPUNIT_ASSERT_MESSAGE( "Test 2: Symbol font flag should be off", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 2: Character set should be RTL_TEXTENCODING_DONTKNOW", + RTL_TEXTENCODING_DONTKNOW, aFont.GetCharSet() ); + + aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + + CPPUNIT_ASSERT_MESSAGE( "Test 3: Symbol font flag should be on", aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 3: Character set should be RTL_TEXTENCODING_SYMBOL", + RTL_TEXTENCODING_SYMBOL, aFont.GetCharSet() ); + + aFont.SetCharSet( RTL_TEXTENCODING_UNICODE ); + + CPPUNIT_ASSERT_MESSAGE( "Test 4: Symbol font flag should be off", !aFont.IsSymbolFont() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Test 4: Character set should be RTL_TEXTENCODING_UNICODE", + RTL_TEXTENCODING_UNICODE, aFont.GetCharSet() ); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/fontcharmap.cxx b/vcl/qa/cppunit/fontcharmap.cxx new file mode 100644 index 000000000..b9d0d8c21 --- /dev/null +++ b/vcl/qa/cppunit/fontcharmap.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +class VclFontCharMapTest : public test::BootstrapFixture +{ +public: + VclFontCharMapTest() : BootstrapFixture(true, false) {} + + void testDefaultFontCharMap(); + + CPPUNIT_TEST_SUITE(VclFontCharMapTest); + CPPUNIT_TEST(testDefaultFontCharMap); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontCharMapTest::testDefaultFontCharMap() +{ + FontCharMapRef xfcmap( new FontCharMap() ); // gets default map + + CPPUNIT_ASSERT( xfcmap->IsDefaultMap() ); + + sal_uInt32 nStartBMPPlane = xfcmap->GetFirstChar(); + sal_uInt32 nStartSupBMPPlane = xfcmap->GetNextChar(0xD800); + sal_uInt32 nEndBMPPlane = xfcmap->GetLastChar(); + + CPPUNIT_ASSERT_EQUAL(static_cast(0x0020), nStartBMPPlane); + CPPUNIT_ASSERT_EQUAL(static_cast(0xE000), nStartSupBMPPlane); + CPPUNIT_ASSERT_EQUAL(static_cast(0xFFF0-1), nEndBMPPlane); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontCharMapTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/fontmetric.cxx b/vcl/qa/cppunit/fontmetric.cxx new file mode 100644 index 000000000..4a3f476c2 --- /dev/null +++ b/vcl/qa/cppunit/fontmetric.cxx @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +class VclFontMetricTest : public test::BootstrapFixture +{ +public: + VclFontMetricTest() : BootstrapFixture(true, false) {} + + void testFullstopCenteredFlag(); + void testSpacings(); + void testSlant(); + void testBulletOffset(); + void testEqualityOperator(); + + CPPUNIT_TEST_SUITE(VclFontMetricTest); + CPPUNIT_TEST(testFullstopCenteredFlag); + CPPUNIT_TEST(testSpacings); + CPPUNIT_TEST(testSlant); + CPPUNIT_TEST(testBulletOffset); + CPPUNIT_TEST(testEqualityOperator); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclFontMetricTest::testFullstopCenteredFlag() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag should be false after default constructor called", !aFontMetric.IsFullstopCentered() ); + + aFontMetric.SetFullstopCenteredFlag(true); + + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag should be true", aFontMetric.IsFullstopCentered() ); +} + +void VclFontMetricTest::testSpacings() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetAscent() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetDescent() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetExternalLeading() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetInternalLeading() ); + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetLineHeight() ); + + + aFontMetric.SetAscent( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetAscent() ); + + aFontMetric.SetDescent( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetDescent() ); + + aFontMetric.SetExternalLeading( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetExternalLeading() ); + + aFontMetric.SetInternalLeading( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetInternalLeading() ); + + aFontMetric.SetLineHeight( 100 ); + CPPUNIT_ASSERT_EQUAL( 100L, aFontMetric.GetLineHeight() ); +} + +void VclFontMetricTest::testSlant() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetSlant() ); + + aFontMetric.SetSlant( 45 ); + CPPUNIT_ASSERT_EQUAL( 45L, aFontMetric.GetSlant() ); +} + +void VclFontMetricTest::testBulletOffset() +{ + // default constructor should set scalable flag to false + FontMetric aFontMetric; + + CPPUNIT_ASSERT_EQUAL( 0L, aFontMetric.GetBulletOffset() ); + + aFontMetric.SetBulletOffset( 45 ); + CPPUNIT_ASSERT_EQUAL( 45L, aFontMetric.GetBulletOffset() ); +} + +void VclFontMetricTest::testEqualityOperator() +{ + // default constructor should set scalable flag to false + FontMetric aLhs, aRhs; + + aLhs.SetFullstopCenteredFlag(true); + aRhs.SetFullstopCenteredFlag(true); + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag set same, aLhs == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Fullstop centered flag set same, aLhs != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetExternalLeading(10); + aRhs.SetExternalLeading(10); + CPPUNIT_ASSERT_MESSAGE( "External leading set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "External leading set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetInternalLeading(10); + aRhs.SetInternalLeading(10); + CPPUNIT_ASSERT_MESSAGE( "Internal leading set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Internal leading set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetAscent( 100 ); + aRhs.SetAscent( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Ascent set same, aLHS == aRhs failed", aLhs.operator ==(aRhs) ); + CPPUNIT_ASSERT_MESSAGE( "Ascent set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetDescent( 100 ); + aRhs.SetDescent( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Descent set same, aLHS == aRhs failed", aLhs.operator ==(aRhs)); + CPPUNIT_ASSERT_MESSAGE( "Descent set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); + + aLhs.SetSlant( 100 ); + aRhs.SetSlant( 100 ); + CPPUNIT_ASSERT_MESSAGE( "Slant set same, aLHS == aRhs failed", aLhs.operator ==(aRhs)); + CPPUNIT_ASSERT_MESSAGE( "Slant set same, aLHS != aRhs succeeded", !aLhs.operator !=(aRhs) ); +} + + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFontMetricTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/gen/data/tdf121120.png b/vcl/qa/cppunit/gen/data/tdf121120.png new file mode 100644 index 000000000..8e48fba38 Binary files /dev/null and b/vcl/qa/cppunit/gen/data/tdf121120.png differ diff --git a/vcl/qa/cppunit/gen/gen.cxx b/vcl/qa/cppunit/gen/gen.cxx new file mode 100644 index 000000000..dfcfaa997 --- /dev/null +++ b/vcl/qa/cppunit/gen/gen.cxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; + +/// This test uses the gen backend (i.e. intentionally not the svp one, which is the default.) +class GenTest : public UnoApiTest +{ +public: + GenTest() + : UnoApiTest("/vcl/qa/cppunit/gen/data/") + { + } + + virtual void setUp() override + { + UnoApiTest::setUp(); + mxDesktop.set( + frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory()))); + SfxApplication::GetOrCreate(); + }; + + virtual void tearDown() override + { + if (mxComponent.is()) + { + closeDocument(mxComponent); + mxComponent->dispose(); + } + UnoApiTest::tearDown(); + }; + + Bitmap load(const char* pName) + { + OUString aFileURL; + createFileURL(OUString::createFromAscii(pName), aFileURL); + mxComponent = loadFromDesktop(aFileURL, "com.sun.star.drawing.DrawingDocument"); + SfxBaseModel* pModel = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pModel); + SfxObjectShell* pShell = pModel->GetObjectShell(); + std::shared_ptr xMetaFile = pShell->GetPreviewMetaFile(); + BitmapEx aResultBitmap; + CPPUNIT_ASSERT(xMetaFile->CreateThumbnail(aResultBitmap)); + return aResultBitmap.GetBitmap(); + } + + uno::Reference mxComponent; +}; + +CPPUNIT_TEST_FIXTURE(GenTest, testTdf121120) +{ + Bitmap aBitmap = load("tdf121120.png"); + Bitmap::ScopedReadAccess pAccess(aBitmap); + const Size& rSize = aBitmap.GetSizePixel(); + Color aColor(pAccess->GetPixel(rSize.getHeight() / 2, rSize.getWidth() / 2)); + // Without the accompanying fix in place, this test would have failed with 'Expected: 255; + // Actual : 1'. I.e. center of the preview (which has the background color) was ~black, not + // white. + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetRed())); + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetBlue())); + CPPUNIT_ASSERT_EQUAL(0xff, int(aColor.GetGreen())); +} + +/// Test that drawing a line preview to a bitmap is not lost. +CPPUNIT_TEST_FIXTURE(GenTest, testTdf107966) +{ + // Set up the virtual device: white background. + ScopedVclPtr pVirtualDevice(VclPtr::Create()); + pVirtualDevice->SetLineColor(); + MapMode aMapMode; + aMapMode.SetMapUnit(MapUnit::MapTwip); + pVirtualDevice->SetMapMode(aMapMode); + pVirtualDevice->SetOutputSizePixel(Size(90, 15)); + pVirtualDevice->SetFillColor(Color(255, 255, 255)); + pVirtualDevice->DrawRect(tools::Rectangle(Point(), Size(1350, 225))); + pVirtualDevice->SetFillColor(Color(0, 0, 0)); + AntialiasingFlags nOldAA = pVirtualDevice->GetAntialiasing(); + pVirtualDevice->SetAntialiasing(nOldAA & ~AntialiasingFlags::EnableB2dDraw); + + // Paint a black polygon on it. + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(0, 15)); + aPolygon.append(basegfx::B2DPoint(1350, 15)); + aPolygon.append(basegfx::B2DPoint(1350, 0)); + aPolygon.append(basegfx::B2DPoint(0, 0)); + pVirtualDevice->DrawPolygon(aPolygon); + + // Make sure that the polygon is visible. + Bitmap aBitmap = pVirtualDevice->GetBitmap(Point(), Size(1350, 15)); + Bitmap::ScopedReadAccess pAccess(aBitmap); + Color aPixel(pAccess->GetPixel(0, 0)); + // Without the accompanying fix in place, this test would have failed with 'Expected: 000000; + // Actual: ffffff', i.e. the top left pixel was white, not black. + CPPUNIT_ASSERT_EQUAL(OUString("000000"), aPixel.AsRGBHexString()); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/graphicfilter/data/README b/vcl/qa/cppunit/graphicfilter/data/README new file mode 100644 index 000000000..2cc9fb3cb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/README @@ -0,0 +1,7 @@ +Files with the string 'CVE' in their name are encrypted to avoid +problems with virus checkers on source code download.; use: + +mdecrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to unencrypt +mcrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to create new tests + +to get access to the plain files for manual testing. diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp new file mode 100644 index 000000000..d77db5782 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2004-0691-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp new file mode 100644 index 000000000..4cfbdfff8 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2006-0006-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp new file mode 100644 index 000000000..289cf8c0e Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-2244-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp new file mode 100644 index 000000000..84ac054db Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp new file mode 100644 index 000000000..a6aed5983 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2007-3741-2.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp new file mode 100644 index 000000000..76aaecf97 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-1097-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp new file mode 100644 index 000000000..d223dde28 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2008-5870-1.bmp @@ -0,0 +1 @@ + î¬.Gx©ŠKØ'seë2Ï~°Œè.G1Ì-”è‚#á›ø1†Y!ðÜÊ¢/ÙDVñ \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp new file mode 100644 index 000000000..b733b2484 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/CVE-2016-10504-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp new file mode 100644 index 000000000..2b58d1035 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp new file mode 100644 index 000000000..cfe7e40f6 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/EDB-24743-4.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp new file mode 100644 index 000000000..1ca6e0008 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/afl-sample-bad-rle-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp new file mode 100644 index 000000000..84b6c35c8 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/crash-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp new file mode 100644 index 000000000..a75d6ebae Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/nodict-compress.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore new file mode 100644 index 000000000..583b009c7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp new file mode 100644 index 000000000..3815a1c13 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2014-1947-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp new file mode 100644 index 000000000..88b11ad57 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf new file mode 100644 index 000000000..a511da43a Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf new file mode 100644 index 000000000..dd57d9102 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf new file mode 100644 index 000000000..8fa6e9377 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf new file mode 100644 index 000000000..6adabec8b Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf new file mode 100644 index 000000000..92da5f05a Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/crash-3.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf new file mode 100644 index 000000000..b89db21c2 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/fdo71307-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf new file mode 100644 index 000000000..634fccdc0 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf new file mode 100644 index 000000000..e3baf3bfa Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/hang-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf new file mode 100644 index 000000000..ef4c6a009 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/fail/slow-moveclip-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf new file mode 100644 index 000000000..c71739a50 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf new file mode 100644 index 000000000..746e85e84 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf new file mode 100644 index 000000000..fbd546cb0 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf new file mode 100644 index 000000000..40f24b41d Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0168-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf new file mode 100644 index 000000000..dcc2a66f7 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf new file mode 100644 index 000000000..b82444a97 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf new file mode 100644 index 000000000..8e67ce5ae Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0169-3.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf new file mode 100644 index 000000000..b17ce7061 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-0170-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf new file mode 100644 index 000000000..0991bba4f Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3301-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf new file mode 100644 index 000000000..78d030daa Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3303-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf new file mode 100644 index 000000000..fadbb7516 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2016-3304-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf new file mode 100644 index 000000000..bbc0285db Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-1.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf new file mode 100644 index 000000000..a52213238 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/crash-2.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf new file mode 100644 index 000000000..0af6c749b Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif new file mode 100644 index 000000000..7e84566e9 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif new file mode 100644 index 000000000..cbefd0162 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif @@ -0,0 +1 @@ +””&‡VâusØ [eë21oæX \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif new file mode 100644 index 000000000..a8f51b6ef --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36334-1.gif @@ -0,0 +1,2 @@ +””&X©=ŠÜØ¿;ekbÎ~§6à*^1Ì.”Ä„#᛾fLt€wüO zØâjA÷–F®HT©Øî +ÞeŸ€Ô ?AäUõaŒÈ»L*ÖVÉqd¦&ó`©6~[­ŠÓ…j™ÜæÏøªÖ`¦µo§D9ëÚ.>4ùÓ \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif new file mode 100644 index 000000000..8f0f4fdb7 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EBD-36335-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif new file mode 100644 index 000000000..d81d3b084 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/EDB-23279-1.gif @@ -0,0 +1 @@ +””&H©1ŠÎØ'[ek2Ι~Ømé®ß1L-h£a[^¦Î.Þð!7¢/&»VOÊ»·BB^ïuËÃî±³È2k]YnEåG)qâ¿ \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif new file mode 100644 index 000000000..26b35e63b Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/fail/too-small-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif new file mode 100644 index 000000000..63426f9d8 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif new file mode 100644 index 000000000..e92a316e4 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif new file mode 100644 index 000000000..190c7b079 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif new file mode 100644 index 000000000..cf4f30c21 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif new file mode 100644 index 000000000..53d2ca01e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif @@ -0,0 +1 @@ +””&t©Š};'[ek2Ι~Ømé®ß1L-h£a[^¦Î.Þð!7¢/&»VOÊ»·BB^ïuËÃî±³È2k]Ynyå°G)‹Ê¿˜ð…‘jkš×Bà:Š’åå¢d#|åµÀu«\#ÑL—®í¢¡µê@Eßý˜ \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif new file mode 100644 index 000000000..7cb2a03d5 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif new file mode 100644 index 000000000..cddbdc357 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/afl-sample-short-read-2.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif new file mode 100644 index 000000000..860f9e1d8 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-1.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif new file mode 100644 index 000000000..b7265f807 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/crash-2.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif new file mode 100644 index 000000000..47f5d4341 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/gif/pass/sf_3e0068c9b19bb548826bed0599f65745-15940-minimized.gif differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg new file mode 100644 index 000000000..c03c8529c Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg new file mode 100644 index 000000000..1a24da322 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-2.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg new file mode 100644 index 000000000..794ff52e4 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-3.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg new file mode 100644 index 000000000..8911646fa Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-4.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg new file mode 100644 index 000000000..c5373df43 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-1097-5.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg new file mode 100644 index 000000000..33bbe9b5f Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg new file mode 100644 index 000000000..e783bd33e Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/crash-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg new file mode 100644 index 000000000..3d9481aca Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg new file mode 100644 index 000000000..5eb27ffb5 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg new file mode 100644 index 000000000..4917f207f Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg new file mode 100644 index 000000000..9d26db005 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-4.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg new file mode 100644 index 000000000..bc668d3e3 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg new file mode 100644 index 000000000..675881f36 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2017-9614-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg new file mode 100644 index 000000000..01e7fe16f Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-2.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg new file mode 100644 index 000000000..4753ed8db Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/EDB-24743-3.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg new file mode 100644 index 000000000..c6ee53505 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/fatalerror-1.jpg differ diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png new file mode 100644 index 000000000..fa90a296f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png @@ -0,0 +1,3 @@ +Àœë#Mb£Š}ÕÔo7ë2ÎË~X¨á.^TÿwBè„!õ›žf1±°ƒÿ»±sé ‘tšùgšça2bA±Õð‡ÁËHbè—"8àî|†ìeGf­S$N0nI€Öªõ +Ôç0"ð—JG°zÀ¤Ü¢(s?d)À"Ëÿ‘GE¢×F¯–9~}–ÇrÕ TÎp?áÅÂ*¿ìò·¥ckµ$E"ŒXï¯8á¾=2±T_3³v¿™#é –á$Hh4«‰JÑKiÝŠJÿ&7r…ú€…Ï=uŠ¯ù69KÙjãûäÎçèÿëWh{‘é½Ï$· dVÅÜ[îÐЖ™Êy\à%Žº%†Ç¾H® meÛÃÞ+ “Á}€ÀgXI¡2ñ>‰*Ä«õ&ù˜Õú›Í· )†Ì¸6ÔpU‚TjODhÙ¶1™éù-ÄÔøø¼Šù¯iŸÐHh“‚×®¦cCߨ?j‡‡aC °Ùε +®¨#êBqŒoìb뀜Ûa6œTâ_‰–ljWõ+¦³ o'”P¨eSÑ%­^̈«%©'™…æÅ_VÇKpJ62AFéÔÅ<+q‰›³Iˆjbö¶n} {êgÌÆ"–û!ˆk[3ÀA²Ã+t}s +¢-·Ò>m=÷÷¢~HZ…§(¾®Þ” Òßfß[ÿcŒ ¬36œ§‹Š†_G¯„ߎ\äÉV@BzyâGßd2Înƒ‡‹)|3 ÃŽcz™¼îâD÷‰¿Ýæ2_æ¨&pN‘xø9YÝXDž`ýFh¿4+·õC^§b×Ë?o +@Öƒˆq \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf new file mode 100644 index 000000000..045f1f45e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/RC4-hang-4.wmf @@ -0,0 +1,3 @@ +ž˜6.Gx©ŠGÓ;>³eë2Î 8Yíà-Ñ1Ì-‘èŠ#ᛞv5."Þ2¢/Ùf_°ÔL½B¡ÎŒÏÄê±´Èi]YowÙ¼(ŽçKP¹ +)W`1a¨%#X„mi×-ã +HŽ‘n<ônÕ~  –ÖáË•©Œ¡Z!> Ø|xíHf}ÐHœôx;ºëcCa¹?jlG‘CLO9VƵ$˜è#äBq—]a¦Ök Ý.²w°Åx”}þ†ˆÆùº¤ß c„461ŠJ‘pHŽÑ«!©'f‡æ¥7VÇWpJp2AFvGÍ<7jú \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf new file mode 100644 index 000000000..2ec88066f Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/bitcount-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf new file mode 100644 index 000000000..02c72ad88 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/exttextout-2.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf new file mode 100644 index 000000000..29c534fdc Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/facename-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf new file mode 100644 index 000000000..f9a72867c Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/ofz5942-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf new file mode 100644 index 000000000..e2fac1523 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/seek-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore new file mode 100644 index 000000000..583b009c7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf new file mode 100644 index 000000000..e70664e64 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf new file mode 100644 index 000000000..cdb09c6b2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf @@ -0,0 +1 @@ +HUÛ¬.DZ©Š¡üI2ÆwÉ~¤ïé._1Ì-œè„#™žf1.!Þ0¢/Ù¸T¸ÊDH½½¡NÏÂî±¼ \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf new file mode 100644 index 000000000..7864da572 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf new file mode 100644 index 000000000..1512a2256 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2015-0848-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf new file mode 100644 index 000000000..365a247a7 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/exttextout-1.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf new file mode 100644 index 000000000..bfd7e20de Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/noheader.wmf differ diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm new file mode 100644 index 000000000..9d2a43470 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/fail/crash-1.xbm @@ -0,0 +1,12 @@ +#define?te_width 31 +#define te_height = { + 0x0e, 0x20, 0x02, 0x38, 0x11, 0x70, 0x07, 0x 0x44, + 0x11, 1x2e, 0x3a, 0x44, 0x8e, 0x24, 0x92, 0x38, 0xdf, 0x25, 0xd2,0x7d, + 0x91, 0x24 0x92, 0x44, 0x95: 0x24, 0x92, 0x54, 0xf5, 0x7f, 0xff, 0x57, + 0x95, 0x24, 0x92, 0x54, 0x95, 0x 4,54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24,x54, 0x95, 0x24, 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24, 0x92, 0x54, 0x95, 0x24, 0x92,0x54, 0x95, 0x24, 0x92, 0x54, + 0x95, 0x24,ÏÏÏÏÏÏÏ 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, 0xf5, 0x7f, 0xff, 0x57, + 0x95,0x24, 0x92, 0x54, 0x95, 0x24, 0x92, 0x54, 0, 0x54, 0xf5, 0xd= { + 25, 0xd2, 0x7d, +0x00, 0x7c }; \ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm new file mode 100644 index 000000000..aad9f0305 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xbm/pass/grafix4.xbm @@ -0,0 +1,2011 @@ +#define Grafix1_width 485 +#define Grafix1_height 395 +static char Grafix1_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, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, + 0x07, 0x00, 0x1c, 0xfc, 0x80, 0x81, 0x03, 0x30, 0x70, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x0c, 0xdc, 0x00, 0x70, 0x00, 0x37, 0x07, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x06, 0x00, 0x18, 0xd6, 0x80, 0xc1, 0x02, 0x30, 0x58, 0x00, 0x00, + 0x00, 0xb0, 0x00, 0x0c, 0xd6, 0x00, 0x60, 0x80, 0x35, 0x06, 0x00, 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, 0x20, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x06, 0x00, 0x18, 0xc2, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x60, 0x80, 0x00, 0x06, 0x00, + 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, 0x20, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x06, 0x00, 0x18, 0xc3, 0x00, 0x60, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x03, 0x00, 0x60, 0xc0, 0x00, 0x06, + 0x00, 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, 0x20, 0x00, 0x58, + 0xf0, 0xe1, 0x63, 0xc1, 0x87, 0x0f, 0x9f, 0xcf, 0xcc, 0xf1, 0xe1, 0x3b, + 0x3e, 0xe0, 0x01, 0x0e, 0x7f, 0xf8, 0x8e, 0xef, 0xe0, 0x63, 0xe6, 0x3b, + 0xe6, 0xe0, 0x33, 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, 0x20, 0x00, + 0x64, 0x98, 0x99, 0x91, 0x61, 0x66, 0x86, 0x19, 0xc3, 0x9e, 0x61, 0x98, + 0x31, 0x0c, 0x30, 0x03, 0x8c, 0x19, 0x66, 0x0c, 0xc3, 0x98, 0x61, 0xcf, + 0x30, 0x46, 0x98, 0xb1, 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, 0x00, 0x20, + 0x00, 0x4c, 0x8c, 0x19, 0x31, 0x31, 0x66, 0xc4, 0x18, 0xc3, 0x99, 0x61, + 0x18, 0x31, 0x0c, 0x18, 0x00, 0xd8, 0x18, 0x46, 0x0c, 0xc3, 0x18, 0xe1, + 0xcc, 0x30, 0x26, 0x18, 0x71, 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, + 0x20, 0x00, 0x1c, 0x8c, 0x19, 0x71, 0x30, 0x66, 0xc4, 0x18, 0xc3, 0x98, + 0x61, 0x18, 0x31, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x46, 0x0c, 0xc3, 0x18, + 0x61, 0xcc, 0x30, 0x16, 0x18, 0x31, 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, 0x20, 0x00, 0x38, 0x8c, 0x99, 0xe1, 0x30, 0x66, 0xc6, 0x18, 0xc3, + 0x98, 0x61, 0x98, 0x31, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x66, 0x0c, 0xc3, + 0x98, 0x61, 0xcc, 0x30, 0x1e, 0x98, 0x31, 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, 0x20, 0x00, 0x70, 0x8c, 0xf1, 0xc0, 0x31, 0xc6, 0xc3, 0x18, + 0xc3, 0x98, 0x61, 0xf0, 0x30, 0x0c, 0x18, 0x00, 0x70, 0x18, 0x3c, 0x0c, + 0xc3, 0xf0, 0x60, 0xcc, 0x30, 0x36, 0xf0, 0x30, 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, 0x20, 0x00, 0x64, 0x8c, 0x11, 0x90, 0x31, 0x46, 0xc0, + 0x18, 0xc3, 0x98, 0x61, 0x10, 0x30, 0x0c, 0x18, 0x00, 0xd8, 0x18, 0x04, + 0x0c, 0xc3, 0x10, 0x60, 0xcc, 0x30, 0x66, 0x10, 0x30, 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, 0x20, 0x00, 0x4c, 0x98, 0xf1, 0x31, 0x61, 0xc6, + 0x87, 0x19, 0xc3, 0x98, 0x61, 0xf0, 0x31, 0x0c, 0x30, 0x03, 0x8c, 0x19, + 0x7c, 0x0c, 0xc3, 0xf0, 0x61, 0xcc, 0x30, 0xc6, 0xf0, 0x31, 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, 0x20, 0x00, 0x34, 0xf0, 0xf3, 0xd7, 0xc0, + 0xcf, 0x1f, 0xbf, 0xe7, 0xb9, 0xf1, 0xf0, 0x37, 0x1e, 0xe0, 0x01, 0x86, + 0x3f, 0xfc, 0x8d, 0xc7, 0xf0, 0xf7, 0xfc, 0x31, 0xc7, 0xf1, 0x7f, 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, 0x20, 0x00, 0x00, 0x00, 0x08, 0x06, + 0x00, 0x20, 0x18, 0x00, 0x00, 0x80, 0x01, 0x08, 0x36, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x0d, 0xc0, 0x08, 0x06, 0x00, 0x30, 0x00, 0x08, 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, 0x20, 0x00, 0x00, 0x00, 0x18, + 0x04, 0x00, 0x60, 0x10, 0x00, 0x00, 0x80, 0x01, 0x18, 0x34, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x0d, 0xc0, 0x18, 0x04, 0x00, 0x30, 0x00, 0x18, + 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, 0x20, 0x00, 0x00, 0x00, + 0x38, 0x02, 0x00, 0xe0, 0x08, 0x00, 0x00, 0xe0, 0x00, 0x38, 0x1e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x07, 0x70, 0x38, 0x02, 0x00, 0x1c, 0x00, + 0x38, 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, 0x20, 0x00, 0x00, + 0x00, 0xf0, 0x01, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x60, 0x00, 0xf0, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x03, 0x30, 0xf0, 0x01, 0x00, 0x0c, + 0x00, 0xf0, 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, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 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, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x7f, 0x00, 0xf0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x55, 0x55, 0x55, 0x55, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 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, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 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, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 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, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xab, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x80, 0x7f, 0x44, 0x44, 0x44, 0xc4, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x7f, 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0xfe, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xfa, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xdf, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xfd, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe3, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xfa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x45, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x71, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x8b, 0xd8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x89, 0xe8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x22, 0x7a, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0x17, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x89, 0x88, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x62, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x11, 0x19, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x88, + 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x44, + 0xc4, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0xf7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0xff, 0x11, 0x11, 0x1d, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0x89, 0x88, 0x88, 0xe8, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x7c, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x23, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x11, 0xd1, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x79, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x8f, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xe4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x50, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xc8, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x7d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x44, 0x74, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, 0xea, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, + 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x17, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x40, 0x55, + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x80, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x26, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2e, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x80, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x89, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xb8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x44, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0xe2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x3f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0xf7, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xaa, 0xaa, 0xaa, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x8b, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x54, 0x55, 0x55, + 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xa8, + 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xa8, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8e, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x50, 0x55, 0x55, 0x55, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x23, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x98, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x6c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x16, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x1d, 0x00, 0x00, 0x80, 0xdf, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x44, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0xd7, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x80, 0x60, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0xe0, 0xba, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x26, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x10, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5f, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xdf, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xb1, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x60, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0xd1, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x3a, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x5c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x50, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x03, 0x80, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x80, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0xc0, 0xa8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xbc, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x4f, 0x44, 0x44, + 0x44, 0xc4, 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x20, 0x22, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x37, 0x22, + 0x22, 0x22, 0x22, 0x7e, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x30, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x51, + 0x11, 0x11, 0x11, 0x11, 0xd1, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x90, + 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xae, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x50, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x45, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x47, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x05, 0x00, + 0x00, 0x28, 0x22, 0x72, 0x77, 0x77, 0x77, 0x77, 0x77, 0x2f, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x62, 0x77, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x15, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x18, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xea, + 0x00, 0x00, 0x00, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8e, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xb8, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x26, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0x23, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x11, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x3d, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x54, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0xdc, 0xdd, + 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x47, 0x44, 0x44, 0x44, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0xa8, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, + 0xba, 0xaa, 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0x23, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x80, 0x89, + 0x88, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, + 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, + 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x45, 0x44, 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, + 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x06, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xbd, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, + 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x88, 0x88, 0x88, 0x88, 0xaa, + 0xaa, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, + 0x22, 0x76, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, + 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x11, 0x11, + 0x11, 0x11, 0x19, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, + 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, + 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xab, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x45, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x35, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x14, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0x8a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x26, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, + 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, + 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0xc8, + 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xba, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, + 0xc4, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xa2, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, + 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, + 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xde, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x19, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0x8d, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, + 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xd8, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0x7d, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x26, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0x9a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0xc4, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x37, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xe2, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x15, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0x9a, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, + 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x62, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x31, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xa8, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x62, 0x77, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x37, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x77, + 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x91, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x6a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc6, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x4c, 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0x23, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x6a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0x8b, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xde, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xba, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xd9, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, + 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xd8, 0x8b, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xbd, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xdd, + 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x44, 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x3a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xb2, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x51, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, + 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0xe2, 0x77, 0x3f, 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x27, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x76, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x91, 0x11, 0xf1, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0x8f, 0x88, 0x88, 0x88, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x5c, 0x44, 0x44, 0x44, 0x45, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x22, 0x22, 0xa2, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x91, 0x11, 0x11, + 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xac, 0xaa, 0xaa, 0x8e, + 0x88, 0xc8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x74, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, 0x77, + 0x77, 0xf7, 0x27, 0x62, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xf7, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x7a, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x39, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0xa8, 0xaa, 0xaa, 0xaa, 0xea, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x4f, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0xf5, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0xdf, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x9d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x7d, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x46, 0x7c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x74, 0x44, 0x44, 0x44, 0x44, 0x44, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x27, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0x23, + 0xa2, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x14, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x3d, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8d, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdf, 0xdd, 0xdd, + 0xdd, 0x88, 0x88, 0xc8, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x8d, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdf, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x54, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x5e, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, + 0xaa, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x38, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x51, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, + 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x57, 0xbd, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xd8, 0xdd, 0xdd, 0xbd, 0x88, 0x88, 0x88, 0x88, 0xf8, 0xdd, 0xdd, + 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x00, 0x70, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x54, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x47, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x47, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xaa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xfa, 0xaa, 0xaa, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xe2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x60, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x1f, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xe8, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xe8, 0xab, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x7e, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0xc4, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0xd5, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x77, 0x77, 0x27, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x3f, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x7a, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xf3, 0x1f, 0x11, 0x11, + 0x11, 0x11, 0x11, 0xd1, 0x17, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, + 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xfa, 0x8f, + 0x88, 0x88, 0x88, 0x88, 0xbe, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x1a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x80, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x46, 0x44, + 0xfc, 0xff, 0x7f, 0xe4, 0xff, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x55, 0xd5, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x76, + 0x77, 0x77, 0x77, 0xf7, 0x7f, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x0d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb0, 0xaa, 0xaa, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xac, 0xaa, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x49, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x4c, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x31, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x7a, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xa2, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xea, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x42, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0x42, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xe2, 0x6a, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x84, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x31, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, + 0x85, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xc8, 0xbd, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0x7d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x08, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, + 0x64, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, + 0xaa, 0xaa, 0x0a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xa2, 0x3a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xba, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x08, 0x14, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x50, 0x55, 0x55, 0x0d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x4e, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0x0a, 0x20, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x26, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x20, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x55, 0x55, 0x15, 0xc0, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8c, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x80, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0x1a, 0x00, + 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x2a, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, + 0x00, 0x12, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, + 0x1a, 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x9a, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x20, 0x00, 0x58, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x65, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0x55, 0x55, 0x35, 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x37, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x03, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x20, 0x00, 0x40, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x31, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xaa, 0xaa, 0x2a, 0x00, 0x80, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0xea, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x45, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x35, 0x00, 0x00, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x62, 0xf7, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x14, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x51, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xa8, 0xaa, 0x89, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x50, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, 0x44, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x00, + 0x00, 0x20, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x72, 0x77, 0x23, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, + 0x00, 0x00, 0xc0, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, + 0x6a, 0x00, 0x00, 0x80, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0xb8, 0xaa, + 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x14, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x2c, 0x22, 0x22, 0x22, 0x22, 0x22, + 0xaa, 0xaa, 0x26, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x15, 0x11, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xa0, 0x88, 0x88, 0x88, + 0x88, 0x88, 0xdc, 0xdd, 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x46, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x80, 0x22, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, + 0x00, 0x8c, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0x8d, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x4c, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x4c, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x22, 0x22, 0x22, 0xe2, 0xaa, 0xaa, 0x2a, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x60, 0x11, 0x11, 0x11, 0x31, 0x11, 0x11, 0x19, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x55, + 0x55, 0x01, 0x00, 0x00, 0x00, 0x80, 0x89, 0x88, 0x88, 0xf8, 0xdd, 0xdd, + 0x8d, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdd, 0xdd, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0x5d, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x46, 0x44, 0x44, 0x54, 0x44, + 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x22, 0x22, 0xaa, + 0xaa, 0xaa, 0x2a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xa2, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, + 0x19, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x91, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x88, + 0x88, 0xac, 0xaa, 0xaa, 0x8a, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x45, 0x44, 0x46, 0x44, 0x44, 0x4c, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x26, 0x22, 0x77, 0x77, 0x77, 0x2f, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x91, 0x11, 0x11, 0x11, 0x19, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xaa, 0xaa, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0xc8, 0xaa, 0xaa, 0xaa, 0x8e, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x75, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x77, 0x77, 0x77, 0x27, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x11, 0x11, 0x11, 0x15, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, + 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xaa, 0xaa, 0xaa, + 0x8e, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0x44, + 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x7d, + 0x77, 0x77, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x77, + 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x30, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, + 0xaa, 0xea, 0xab, 0xaa, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x4e, 0xc4, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x46, 0x44, 0x44, 0x44, 0x44, 0x44, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xac, 0xaa, 0xaa, 0xfa, 0x6a, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x13, 0x11, 0x11, 0x11, 0x11, 0x71, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x01, 0x00, + 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xbd, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0x5f, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x45, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xe4, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, + 0x06, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x3e, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0xae, 0xaa, 0xaa, 0xaa, 0xbe, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0xe0, + 0x13, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x11, 0x11, 0xf1, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, + 0x55, 0x55, 0x35, 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x1f, 0x00, + 0x00, 0xfc, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xdc, 0xdd, 0xdd, + 0x5f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x4f, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x44, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x3e, 0xc0, 0xab, 0xaa, 0xaa, 0xaa, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0xaa, + 0xea, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x99, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x58, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x88, 0x88, 0x88, + 0x88, 0x7f, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0x7f, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x58, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x70, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x55, 0x55, 0x55, 0x55, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x0d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaa, 0xaa, + 0xaa, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xaa, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x56, 0x55, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x57, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x75, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x1d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xb0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 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, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x01, 0x00, 0x00, 0x00, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x55, 0x55, 0x55, 0x3d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xaa, 0xaa, + 0xea, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, + 0x7f, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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}; diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm new file mode 100644 index 000000000..ca2d777a1 Binary files /dev/null and b/vcl/qa/cppunit/graphicfilter/data/xpm/fail/gentoo22729-1.xpm differ diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/indeterminate/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm new file mode 100644 index 000000000..b5eab3e33 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/xpm/pass/tdf111925-1.xpm @@ -0,0 +1,306 @@ +/* XPM */ +static char * example_xpm[] = { +"150 100 203 2", +" c #E6DECA", +". c #E5DDC9", +"+ c #E4DCC8", +"@ c #E3DBC7", +"# c #E3DAC5", +"$ c #E2D9C4", +"% c #E1D8C3", +"& c #E1D7C1", +"* c #DFD6C1", +"= c #DFD5BF", +"- c #DED4BE", +"; c #DDD3BD", +"> c #DDD2BB", +", c #DCD1BA", +"' c #DBCFB9", +") c #DACFB8", +"! c #D9CDB7", +"~ c #D8CDB6", +"{ c #D6CAB2", +"] c #D7CBB3", +"^ c #D7CCB5", +"/ c #D5C9B1", +"( c #D4C8B0", +"_ c #D3C7AF", +": c #D3C6AD", +"< c #D2C5AC", +"[ c #D1C3AB", +"} c #D0C2AA", +"| c #CFC1A9", +"1 c #CEC0A8", +"2 c #CDBFA7", +"3 c #CBBDA5", +"4 c #CCBEA6", +"5 c #CABBA2", +"6 c #C9BAA1", +"7 c #CBBCA3", +"8 c #C8B9A0", +"9 c #C7B89F", +"0 c #C6B79E", +"a c #C5B69D", +"b c #C5B59B", +"c c #C4B49A", +"d c #C3B399", +"e c #C2B298", +"f c #C1B197", +"g c #C0B096", +"h c #BFAF95", +"i c #BEAE94", +"j c #BDAD93", +"k c #BDAC91", +"l c #BCAB90", +"m c #BBAA8F", +"n c #BAA98E", +"o c #B9A88D", +"p c #B2A186", +"q c #B3A287", +"r c #B8A78C", +"s c #B6A58A", +"t c #B2A084", +"u c #B09E82", +"v c #AF9D81", +"w c #B5A489", +"x c #7F6B4B", +"y c #5F4E2D", +"z c #5E4D2C", +"A c #614F2D", +"B c #A39175", +"C c #9D8B6F", +"D c #978265", +"E c #927E5E", +"F c #8C7858", +"G c #857151", +"H c #7A6746", +"I c #776443", +"J c #887454", +"K c #E7DFCB", +"L c #1E1800", +"M c #161100", +"N c #221B00", +"O c #AB997D", +"P c #9A876A", +"Q c #948060", +"R c #8A7656", +"S c #816D4D", +"T c #796645", +"U c #715E3D", +"V c #685534", +"W c #584826", +"X c #725F3E", +"Y c #B19F83", +"Z c #E8E0CC", +"` c #B7A68B", +" . c #120F00", +".. c #000000", +"+. c #AC9A7E", +"@. c #937F5F", +"#. c #826E4E", +"$. c #6F5D3D", +"%. c #E9E1CD", +"&. c #AD9B7F", +"*. c #9B896D", +"=. c #847050", +"-. c #7A6848", +";. c #6A5838", +">. c #61502F", +",. c #5B4A29", +"'. c #746140", +"). c #AE9C80", +"!. c #968164", +"~. c #8E7A5A", +"{. c #897555", +"]. c #8B7757", +"^. c #836F4F", +"/. c #7D6949", +"(. c #9F8D71", +"_. c #907C5C", +":. c #A9977B", +"<. c #A08E72", +"[. c #9A8568", +"}. c #988366", +"|. c #A29074", +"1. c #9B886B", +"2. c #958161", +"3. c #695635", +"4. c #665534", +"5. c #756241", +"6. c #9C8A6E", +"7. c #625130", +"8. c #766342", +"9. c #6B5939", +"0. c #7E6A4A", +"a. c #6A5736", +"b. c #786544", +"c. c #A79579", +"d. c #998467", +"e. c #B4A388", +"f. c #A59377", +"g. c #493A13", +"h. c #3A2D00", +"i. c #413509", +"j. c #362B00", +"k. c #6D5B3B", +"l. c #52431E", +"m. c #382D00", +"n. c #282000", +"o. c #403306", +"p. c #5D4C2B", +"q. c #73603F", +"r. c #4A3B14", +"s. c #1A1500", +"t. c #544422", +"u. c #8F7B5B", +"v. c #7C6948", +"w. c #51421D", +"x. c #3C3000", +"y. c #534321", +"z. c #241C00", +"A. c #3E3202", +"B. c #655433", +"C. c #574725", +"D. c #50411C", +"E. c #53441F", +"F. c #6E5C3C", +"G. c #554523", +"H. c #4D3F19", +"I. c #4F3F19", +"J. c #A49276", +"K. c #A8967A", +"L. c #302600", +"M. c #473911", +"N. c #0E0B00", +"O. c #3F3203", +"P. c #080600", +"Q. c #42340A", +"R. c #4B3C15", +"S. c #43350B", +"T. c #877353", +"U. c #5C4B2A", +"V. c #46370E", +"W. c #4C3E18", +"X. c #322700", +"Y. c #50401A", +"Z. c #645332", +"`. c #2A2100", +" + c #2E2500", +".+ c #645230", +"++ c #A69478", +"@+ c #867252", +"#+ c #5A4826", +"$+ c #463810", +"%+ c #A18F73", +"&+ c #806C4C", +"*+ c #403204", +"=+ c #413407", +"-+ c #9E8C70", +";+ c #958263", +">+ c #AA987C", +",+ c #5A4928", +"'+ c #564624", +")+ c #4C3D16", +"!+ c #483912", +"~+ c #6C5A3A", +"{+ c #8D7959", +" ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + + + + + + + . . . . . . . . . . . . . . . . . . + + + + + + + . . . . . . . . . . . . . . . . . . + + + + + + + + + + + . . . . + . . . . . ", +" . . . . . . + . . . . . . . . . . . . . . . . . . . . . . . . + + + + + + + + . . . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ @ @ @ @ @ @ @ + + + + + + + . . . . . . . . ", +" . . . . . + . + + + @ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ @ @ @ @ @ # # # # # # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # # # # # @ @ @ @ + @ + + . + . . . . ", +" . . . . + . + + + + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # # # # # # # # # # # # # # # $ $ $ $ $ % % % % $ $ $ $ $ # # # # # # # # # # # $ $ $ $ $ $ % % % $ $ $ $ $ # # # # # # # # # # # $ $ $ $ % % % % % % % % % $ $ % $ # # # @ @ @ + + + . . . . . . ", +" . . . . . + . + @ + @ @ # # # # $ $ $ $ $ $ $ # # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ % % % & & & & * * * * * * & & & & % % % $ $ $ $ $ % % % % & & & * * * * * * & & & & % % % $ $ $ $ $ % % % & & & * * * * * = = * * * * & & & % % $ $ # # @ @ + + . + . . . . ", +" . . . . + + + + @ @ # # $ $ % % % % % % % % % % % % % $ $ $ % % % % % % & & & & & & & & & & & & & & * * * = * = = = = = = = = = * * = * * * & & & & & * * * = * * = = = = = = = = * * = * * * & & & & & * * * = * = = = - - - - - - - - = = * = * * & % % $ # # # @ @ + + . . . . ", +" . . . . + + @ @ @ # # % % % & & & * * * * * * * * * & & & & & & * * * * = * * * * * * * * * * * * = * = - - ; ; > ; > > , > > > > ; ; - - = = * * * * * = = - - ; ; > ; > > > > ; > ; ; - - = = * * * * * = = - - - ; ; > , ' ' ' ' ' , , > > - - - = * * & & % $ # # @ + + + . . . . ", +" . . . . + + @ @ # # $ % & & = = * = = = - - - - = = = = = = = = = = = - - - - ; ; ; ; ; ; ; ; ; ; ; ; ; > , ' ' ) ) ) ! ! ! ! ! ! ! ) ' ' , > > ; - - - ; > > , ' ) ) ! ! ! ! ! ! ! ! ) ' ' , > > ; - - ; ; > > , ) ) ) ! ! ! ! ~ ~ ~ ! ! ! ! ) ) ' > ; - = * * & % $ # # @ + + + . . . . ", +" . . . . + + + # # $ % % & * * = - ; ; ; > > , , > > > ; > ; ; ; ; > ; > , ' ' ) ) ) ) ) ) ) ) ) ) ) ) ) ! ! ! ! ~ ~ { { { { { { { { ] ~ ~ ! ! ) ) ) ) ) ) ' ) ! ! ~ ~ ^ ] { { { { / { { ~ ~ ! ! ) ) ) ) ) ) ) ! ! ) ~ ^ ^ { { / { { / { { / { ] ^ ~ ! ! ) ' ; ; = * * & % $ # # + + + . . . ", +" . . . + + @ @ # $ % & = * = ; > , ) ) ) ! ! ! ! ! ! ! ! ) ) ) ) ) ! ! ! ) ! ! ~ ~ ^ ^ ^ ^ ^ ^ ~ ~ ~ ^ ^ ] { / { / ( ( _ _ _ ( _ _ : ( ( / { { ] ^ ^ ~ ~ ~ ~ ^ { { { / ( ( _ _ _ _ _ _ ( / / { { ] ^ ^ ~ ~ ~ ~ ^ { { { / ( _ _ _ : _ _ : _ _ _ ( / / { { ~ ! ) ' > - = * & % $ # @ @ + + . . . ", +" . . . . . @ @ # $ % * * = - ; , ) ! ! ~ ^ ^ { { ] ] { ^ ^ ~ ~ ~ ~ ^ ^ ] { / { { / / ( _ ( _ ( ( ( ( ( ( _ _ _ _ _ < [ [ [ } | | | } [ < < : _ _ ( / / / { / ( ( _ _ _ < [ [ [ } } } } } [ [ : _ _ ( / / / { / ( ( _ _ _ < [ } } 1 | | | | 1 1 } [ < : _ / { ] ~ ! ) > ; * * & % # # @ + + . . ", +" . . . + + @ @ # % & * * - > ' ) ! ~ { / / / / ( ( ( ( ( / ( ( ( / ( ( _ _ ( _ : [ [ [ [ < < [ [ [ [ [ [ < [ } 1 1 1 2 2 2 3 3 3 3 3 2 2 1 | | [ [ < : _ _ _ _ < < [ 1 | 2 2 2 2 3 3 2 1 2 1 | | [ [ < : _ _ _ _ < < } | 1 1 2 3 3 4 3 3 4 3 3 2 2 | | < < _ ( { ^ ! ) , - * * & $ # # + + + . . . ", +" . . . + @ # $ $ & * = ; > ' ) ~ { { ( _ _ : < [ [ [ [ [ [ < < < [ [ [ [ [ | | | 1 2 2 2 1 2 2 2 2 1 1 2 2 2 2 3 4 5 5 6 5 6 6 6 6 6 6 5 7 4 2 1 1 | | | | | | 1 2 1 3 3 5 5 5 5 5 6 5 5 7 5 4 2 1 1 | | | | | | 1 2 2 4 5 7 5 5 8 8 6 8 8 6 5 5 5 4 2 2 | [ : ( { ] ! ) , - = * % $ # @ @ . . . ", +" . . . + + @ # $ % * * - ; ) ! ] { / ( < [ [ | | | 1 1 1 1 1 1 1 1 1 2 2 1 2 3 3 5 5 5 5 5 6 6 5 5 7 5 5 5 5 5 5 8 6 9 0 0 a a 0 0 a 0 0 9 9 8 5 5 7 3 3 4 4 3 4 3 7 5 5 8 9 0 0 0 0 0 0 0 9 6 5 5 5 7 3 3 4 4 3 4 3 7 5 5 6 8 0 0 0 a b a a a 0 9 9 6 7 3 2 1 [ < ( { ] ) ' > = * & % # @ + + + . . . ", +" . . . @ # $ $ % * = ; ' ! ] { ( _ < | 1 2 2 3 3 3 3 7 7 7 7 3 5 7 5 5 6 5 8 8 9 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 b a c c d c c e c c d c b a 0 9 8 6 8 5 5 5 5 8 6 8 9 0 a b c c d d d c c c a 0 9 8 6 8 5 5 5 5 8 6 8 9 0 a b c d d e e e c c c c 0 9 9 5 7 4 1 } < ( { ~ ) ' ; = * % $ # @ + + . . . ", +" . . + + + @ $ % & * - , ) ~ { ( : < | 1 3 5 5 5 5 6 8 8 8 8 8 8 9 9 0 0 0 a b a b c c d c c c c d d c c d c c d d f f f g g g g g g g f e d c c c b 0 0 0 0 0 0 a b c c d e e g f g f g e e d c c a b 0 0 0 0 0 0 a b c c d f g g g g g g g g f d c b 0 9 6 5 4 1 | < ( ] ~ ) , = * & $ # @ + + + . . ", +" . . . + + @ # $ % * = ; ) ~ ] ( : } 1 4 7 5 8 0 9 0 0 a a a b b a b c c c d e d f f f g g g g g g g g g g g g g h h i i i j j j j j j i h h g g e c d c c c b c c d d e g g h h i h h i h g g f f e d c c b c c c c d d e f g h h i i j j i i i g g g c c 0 9 8 5 4 1 < _ / ^ ) , - = * % $ # @ + + . . ", +" . . . . @ # # % * * ; , ) ^ / _ [ 1 4 7 5 8 0 0 a c c d d d e d f e f f f g g i i i i j j j j j j j j j j j j k j j k l k l l l l l k k j j i i g g f f g e e f g g g h h i j j j k k j j j j i i h g f f g e e f g g g h h j j j j l k l j j j j h h f e b a 9 5 7 2 } : ( ] ! ) ; = * % $ @ @ + . . . ", +" . . + + @ $ % * * ; ' ! ] ( : } 4 3 5 9 0 b d d e f g g g g g h i i j j j j j j k l m l l l l l m l l l l l m m m m n m m m m m m m m l m k j j i h i h h h i h h i j j k k l l m m l l l k k j j i h i h h h i h h j j k j k l m m m m l l k k j i g f d c a 8 5 3 1 [ ( { ^ ' , - & & % # @ + . . . ", +" . . + + @ # $ % * = , ' ^ { ( [ | 3 5 8 0 b c e g g i i j j j j k k k l k m m m m m n m n m n m n m m n n m m m m m n n n n n n n n m m m m l k l j j j j j j j j j j k k m l m m m m m m m m l l k j j j j j j j j j j k k l m m m m m m m m m k j i h g e c b 0 5 3 1 } _ ( ] ! , ; = & % $ @ + + . . . ", +" . . + + @ # $ & & = , ) ^ ( : [ 1 7 5 0 b d e g h i j l k m l l m m m n m m m n n m m n n n o o o n n o o o n o n n n n n o o n n m m n m m m m m m l k k k k k l k l l m m m m m m m m m m m m m l l l l k l k k l k l l m m m m m m m m m m m l k j i h f c c a 9 7 4 | : ( ] ! ' ; = & % # @ + + + . . ", +" . . + + @ # $ & * - , ) ] ( [ | 2 5 8 0 c e g h j j k m m m n n m n n n n n n n n n n n n n n m n n n m n n n n n m m n m m m m m m m m m m m m m m m m m m l m m l m m m m m m m m m m m m m m m m m m m m m l m m l m m m m m m m m m m m m m l k j j h g d c a 8 5 3 1 [ _ ] ~ ' ; = * % $ # @ + + . . ", +". . . . @ @ # % * = - ' ~ / ( < 1 4 6 0 b e f g j j l l m m m n n n o n n n m m n m m m m m m m l m m m m m m m m m m l m m m l l m m m m m m m m m m m m m m m m m m m m l m m m m m m m m m m m m m m m m m m m m m m m m l m m l l l l m m l l l k j j h g f d b 0 6 7 1 [ _ / ^ ' , = & & $ @ @ + . . ", +". . . . + @ $ % * = > ' ~ / ( } 1 7 6 0 c e g h j k l m m n n n n n n m m m m m l l k k k j j j j j j j k k k k k j j j j j j j j j k k k l m m m m m m m m m m m m l m l l l k k k k l l l l m m m m m m m m m m m m l m l k l k k k k k l l k k k j j j i g f d c 0 5 3 1 } : / ^ ) , - * % $ # @ + . . ", +". . . . + @ # % * = , ' ~ / : } 1 7 8 0 c e g i j k l m m n n m m m m m l k k j j i i h g g g g g g g g g g h h g g g g g g g g h i i j j j k k l m m m m m m m m l k k k j j j j j j j j j k k l l m m m m m m m m l k k k j j j j j j j j j j j j j j i h g g d c 0 9 5 4 | < ( ] ! ' - * & % # @ + . . ", +". . + + # $ % & = , ' ^ / < | 1 5 9 b c f g i j k l m m m m m l l k j j i h g g g e d d d d c c c c c d d d d d d d c c d d d e e g g g h j j j k l k l l k k k k j j j h h g g g h g h i i j j k k k l l l k k k k j i i h h h g g g h g h h i i j i i h g f d c a 9 6 3 | < _ { ~ ' ; * * % # # + + + . ", +". . + + # $ & & = , ' ^ ( : | 4 5 9 a c e g i j j k k l l k k j i h h g f e d c c a 0 0 0 0 9 9 9 9 0 0 0 0 0 0 0 0 0 0 0 a a b c c d e g g h i i j j j j j j j i h h g g f e e e e f f g g h i i j j j j j j j j i h g g f f e f e e f f g g g h g h h g g f e c 0 9 5 4 1 [ _ / ^ ) , = & & $ @ @ + . . ", +". . + @ @ $ % & - , ' ^ ( : 1 2 5 9 a c e g h i j j j j j i i g g f e c b a 0 9 8 5 5 5 5 7 7 7 7 7 7 7 7 5 5 5 5 5 5 5 5 6 8 9 9 0 a c c d e g g g i h h h h g g f e d c c b c b c c c d d e g g g h h h h h h g g f e d c c c b c c c c d e f g g g g g g f d c b 9 8 7 2 | < / ^ ) , - * & $ # @ + + . ", +". . + @ @ # % & = , ! ] ( < | 4 5 9 a c e f g h i i h h h g f e d b a 0 9 6 5 7 4 2 2 1 1 | | | | | | | | 1 1 1 1 1 1 2 2 4 3 7 5 6 8 0 0 b c c e e f f f f e e d c b a 0 0 0 9 9 0 0 0 a b c c d e f g f f f e e d c c a a 0 0 0 0 0 0 a b c d d e f g g f f d d b 0 6 5 4 | < ( ] ~ ' ; * * % $ # @ + + ", +". . + + @ @ $ & * - , ! ] ( < | 2 5 8 0 c d e g g g g g f e e c b 0 9 8 5 3 4 1 1 | [ < : : _ _ ( ( ( ( _ _ _ _ : : < < < } } | 1 2 4 7 5 6 9 0 a b c c c c c b b a 0 9 8 6 5 5 5 5 5 5 8 8 9 0 0 a c c c c c c b b 0 0 9 8 8 6 5 5 5 6 8 9 9 a b c d d f f f e d c b 0 8 5 3 1 [ ( / ^ ' , - * & $ # @ + + ", +". . + + @ @ $ & * - , ! { ( : 1 2 5 8 0 b c d e e f e e d c a 0 8 6 5 3 1 1 } < _ ( ( / { ] ^ ] ] ] ] ] ] ] { { ] { { / ( ( _ : < } | 1 4 3 5 5 8 9 9 0 0 0 0 0 8 8 5 5 7 3 4 2 2 2 2 4 3 7 5 6 6 8 0 0 0 0 0 0 9 8 8 5 5 7 3 3 4 4 3 3 7 5 5 9 0 a b c d d e e d c c a 9 5 7 2 | < / ] ! ' - = * % $ # @ + ", +". . + + @ # $ & & - , ! ] / : 1 4 5 6 0 a c c d d c c c b 0 9 6 5 3 1 | [ : ( ( ] ^ ~ ! ) ) ' ) ' ' ' ' ) ) ) ' ) ) ! ~ ^ ^ ] { ( ( : [ } 1 2 4 7 7 5 5 5 5 5 5 3 3 2 2 1 1 } | } } | | 1 1 2 4 3 7 5 5 5 5 5 5 5 3 3 2 2 1 | | | | | 1 1 4 7 5 6 0 0 b c d d e d c c a 0 8 5 4 | [ _ / ^ ) , - * & $ $ @ + ", +". . + + @ # $ & & = , ! ] ( : | 2 7 8 9 a b c c c c a 0 0 8 5 3 2 1 [ : ( / ] ~ ! ' , , > ; ; - - - - - - - ; ; ; > > , , ' ! ! ^ { / ( _ < } } 1 1 1 2 2 2 1 1 1 | } [ < : _ _ ( _ _ : < < } | | 1 2 2 2 2 2 1 1 1 | | [ < : : : : < < } 1 1 3 5 6 9 0 b c c d d d c b 0 8 6 3 2 | < ( ] ! ) ; = * % $ $ @ ", +". . + + @ # $ % & = , ! { / : | 2 7 5 9 0 a b b a a 0 9 6 5 4 1 } : ( / ] ~ ) ' > - - = * & & & % % % % & & & & * * = = - ; > , ) ! ~ ] { ( _ _ < [ } } } } [ [ < _ _ ( ( / / { { { / / / ( _ : : < [ } } } } } [ < : _ ( ( ( ( ( ( ( ( _ < } 1 4 5 5 9 0 a c c c c c b a 0 6 7 4 | } ( ( ] ) ' - * & % $ # ", +". . + + @ # $ % & = , ! ] / : | 1 3 5 9 0 0 0 a 0 9 8 5 7 4 1 } : ( { ^ ) ' > - = * & % $ # # # # @ @ # # # # # $ $ % % & * = - ; > ' ! ~ ^ ] / ( ( ( ( ( ( ( ( ( / { ] ^ ^ ~ ~ ~ ~ ~ ^ ] ^ { / ( ( ( ( ( ( ( ( ( ( / { { ] ( ( ( ( ( / ( _ : [ 1 4 5 6 0 0 b c c c c c b 0 9 5 3 1 } < ( ] ^ ) ; = * & $ # ", +". . + + @ # $ & & = , ! ] / : | 2 5 6 9 0 a a a a 0 9 5 3 1 [ : ( ] ~ ' , - = & % $ # @ @ + + + . . . . + + + + + @ @ # $ $ % & = - ; > , ) ! ~ ^ ] ] ] { ] ] ^ ^ ~ ! ) ' , , ' , ' , , ' ) ! ~ ^ ^ ] ] { { ] ] ^ ^ ~ ! ! | m p q q m 1 { / ( : [ 1 3 5 8 0 0 b c c c c b 0 0 8 5 3 1 } _ ( ^ ) ' ; = * % $ ", +". . + + @ @ $ & & = , ! ] / : 2 a i m r s q t u v v w b 1 } : ( ] ~ ' > - = % % # @ + . . . . . + + @ # $ % & * = ; > , , ' ' ) ) ) ) ' ' , > , > ; ; - - - - - ; ; > , ' , ' ' ) ) ) ) ' ' , , > ' j x y z A x l ] ^ / ( < | 1 3 5 9 0 a b c c c c b a 8 6 3 2 } [ ( ] ^ ) ; = * % $ ", +". . + + @ @ $ & * - , ) ] / : 6 t B C D E F G x H I J s 1 < ( / ~ ) , - * % # # + . . K K K K K K K K K K K K K . . + @ # $ % & & * = - ; ; ; > > > ; ; - - = = * * & & & & & * * = = - - ; ; > > > > ; ; - - = , s y L M N A w ^ ) ^ / _ < 1 4 7 6 0 a b c c c c b 0 9 8 7 4 1 [ _ / ] ) , - * & $ ", +". . + @ @ # % & = , ! ^ / : 0 O P Q R S T U V y W X Y 1 _ ( ] ) , ; * % $ @ + . K K Z Z Z Z Z Z Z Z Z Z Z Z Z Z K K K . . + @ @ # $ % % & & * * * * * * * & & % % $ $ $ $ # $ $ $ $ % % & & * * * * * * * * & & % - ` z ...M y s ) ' ! ] ( : } 1 3 6 9 0 b c c c c c a 0 9 5 3 1 } < ( ] ! ' ; = * & ", +". . + @ # $ % & = , ) ~ / : 9 +.P @.R #.T $.V z W X Y 1 ( / ~ ' > - & $ # + . K K Z Z %.%.%.%.%.%.%.%.%.%.%.Z Z Z Z K K K . + + @ @ # # $ $ $ $ $ $ $ $ # # # @ @ @ @ + + @ @ @ @ # # # $ $ $ $ $ $ $ $ $ $ # # * r z ...M z s ' > ' ~ { ( [ | 4 5 8 0 a c c c c c c 0 0 6 7 4 1 [ _ ] ^ ' , = * % ", +". . + + # $ % & = > ' ~ / _ 9 &.*.Q F =.-.X ;.>.,.'.t | ( ] ! , - * % # @ . . K Z Z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.Z Z Z K K . . + + + @ @ @ @ @ @ + + + + . . . . . . . . . . . + + + @ @ @ @ @ @ @ @ + + + % o y ...M y ` > - , ! ] ( : } 2 7 6 0 a c c d d c b a 0 8 5 4 1 [ _ ( ] ) , - * & ", +". . . + # # % & * > ' ~ ] ( 8 ).C !.~.{.].{.^./.H R r [ / ^ ) > - & % # + . K Z Z %.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.Z Z Z Z K K K . . . . . . . . . . . . . . . . . . . . . . . $ n y ...M y r ; - > ) ~ / _ } 1 3 6 9 0 b c c d c d a 0 8 5 3 2 | : / ^ ! ' - * & ", +". . . . + @ # % & * > , ! ] ( 6 v (.D _.Q :.q q p p r 6 < _ / ^ ! ' = $ # + . . . + + . . Z Z Z K . . . K K . . . . . Z K K K + + @ @ @ . . @ # # # + . . + @ @ @ . K K @ @ @ @ @ + + @ # # # @ . K @ m y ...M y r - = ; ' ^ / < 1 3 5 9 0 b c d d d c c b 0 0 5 3 1 } : / ] ) ' ; = & ", +". . . . @ @ # % & * > , ~ ] ( 5 Y <.[.@.}.s 9 6 5 7 4 | 1 g ` w s l 2 ; @ + . & [ g l l h 2 & Z * } c j h 9 / ^ b l l l a > Z Z > b m m m c ) ; | e j d [ * + * } d j c _ $ K K Z K , b m m m c ! ; 1 f j e | - + @ m A ...M y r - * - ' ~ _ 5 j q u u q m g d d d c c b 0 0 5 3 1 } : / ^ ! ' ; = & ", +" . . + + @ # $ & * - , ! ] ( 5 q |.1.2.[.r 9 6 5 7 1 | 0 <.H 3.4.5.6.5 & + % 3 *.X >.7.8.B ( . , k !.I V 9.S (.O 0.7.A 7.^.a a ^.7.A 7.S r o !.I a.T *.0 { j !.b.;.H (.4 @ Z %. a ^.7.A 7.S o r Q 5.3.b.!.j , K + m A ...M A o = & - , ( d c.~.T X I G d.&.l f d c c b 0 0 5 3 1 } : / ] ) ' ; = & ", +" . . + + @ @ $ % * = , ) ~ / 3 e.f.C !.d.&.s s e.n 8 } 3 O 5.g.h.i.9.:.( $ ( c.4.j.M h.k.t , - n ^.l.m.L n.o.p.q.r.M .L 7.k . . k 7.L .s.t.u.v.w.m.N x.y D :.=.y.m.z.A.B.c.^ K %.. k 7.L .s.C.@.0.D.j.N m.E.G l = Z + m A ...M A o = * - ^ e [.F.G.H.I.E.z $.R J.m e c b c 0 9 5 3 2 | : / ^ ! ' - * & ", +" . . + + # # % & = > , ! { 4 ` K.(.[.2.2.E F J @.m [ < c }.p.A.L.M.x n ( r H o.N.s.y.d.| $ 5 u.I.s.........z.O.N .... .A l . . l A ...P.x.t.Q.M ....P.m.,.;.R.L ....P.S.T.5 %.. l A ...P.o.U.M.s.......L D.E 3 . . m A ...M A o * * ; 3 C V M.i.V.R.D.t.p.9.J K.j c c a 9 9 5 3 1 [ _ ( ] ' , = & & ", +" . . . . @ @ $ % & * ; , ! ] 1 o O |.1.2.~.G v.5.=.s } _ [ r =.W.X.X.t.@.p _.Y.M N.Q.S h & > v Z.n.......P.N.N.N....... .A l . . l A ..... .z.s.P.......N.`.m.N P....... +U f . %.. l A .....M +L N.P.......`.V p - + l A ...M A o * * ~ w I M.A.S.y.B.a.>.z .+5.Q q d c 0 9 6 5 2 1 < _ ] ^ ' , = * % ", +" . . . + + @ # % & & - , ' ^ } l &.++C D _.T.0.8.@+s | _ ( 4 c.9.o.`.m.A #.p.`.P. +4.O ! . < !.W.N...N.h.D.#+D.h.N..... .A l . . l A .....N $+l.V.L ......N M.E.$+N ....s.Z.j . %.. l A ..... .x.w.#+D.m.N...N.I.d._ @ l A ...M A o * = 1 1.W x.A.D.x C C ^.V Z.F.@+:.h a 0 8 5 3 2 } < ( ] ! ' ; = * & ", +" . . + + @ # $ % & * ; , ! [ i Y :.%+[.@.].#.H J ` [ ( / / c Q C.X.z.x.g.m.N.s.D.2.4 + 9 &+*+P...m.;.*.v *.a.m..... .A l . . l A ...P.$+=.(.^.V.P...P.M.@+%+@+M.P... .>.l . %.. l A .....m.9.6.v 1.3.j...P.=+^.8 # l A ...M A o * - c G g.m.*+z *.j l *.X 4.k.&+(.k 0 9 6 5 4 1 [ _ / ^ ) ' - * & $ ", +" . . . + @ $ % & & - , ) : g q +.B -+C P ;+_.}.k [ ( / ~ ( s /.$+z.L s. .N.=+v.m & Z . f $. +..N.I.d.4 ; 4 d.I.N... .A l . . l A ... .W O } >+W ... .W O [ O W ... .A l . %.. l A ...N.Y.[.2 ; 3 }.I.N...L.X e # l A ...M A o * ; k '.i.j.*+z D +.O d.X V F./.[.n 0 0 5 3 2 | < _ / ^ ' , - * & % ", +" . . . + + @ @ $ % & = > ' ( d s v c.c.` i j m i 7 : / ] ~ ! 1 %+y j.s. .N.z.p.J.{ K Z . j 4.L .. .,+Y = K = Y ,+ ... .A l . . l A ... .y o = o y ... .y o = o y ... .A l . %.. l A ... .,.t = K = Y ,+ ...N V i $ l A ...M A o * ; o a.x.j.A.R..+F.X $.4.V $./.!.r 0 6 5 4 1 [ < ( ^ ! ' ; = * & $ ", +" . . . + + @ # $ % & * ; , ( c r u :.O e 1 | | | < _ / ] ~ ) / q U O.L M N.j.F.r * Z Z . k .+s... .z ` # Z # ` z ... .A l . . l A ... .A m $ m A ... .A m $ m A ... .A l . %.. l A ... .z r # Z # ` z ...s..+j $ l A ...M A o * ; r 4.m.j.A.Q.R.D.'+p..+a.X /.;+o 0 5 5 2 1 [ ( / ^ ) , ; = & % $ ", +" . . . + + @ $ % & * = , / b o p O &.c | [ < < _ ( / ] ! ) 1 %+A j.L M N.z.p.J.{ K Z . j V N .. .#+v - K = u ,+ ... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ... .,+Y = K - v #+ ...N V j $ l A ...M A o * ; o 9.A.j.A.R..+F.'.b./.S J ~.-+l 9 5 7 2 | : ( / ^ ' , = * & % # ", +" . . . @ @ # $ & * = > ] 0 m q +.&.c | | } [ [ _ ( ] ~ ( ` 0.M.`.n.X.L N.=+v.m & Z . e X L...N.H.!.7 - 4 }.I.N... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ...N.I.}.2 - 7 !.H.N...L.X e # l A ...M A o * - j I Q.j.o.p.2.O v u u v t q o c 6 5 4 2 } : ( { ~ ' , = * & % # ", +" . . . + @ @ # $ % & * > ] 0 m q &.+.m f h j l g 2 / ] ] b ;+#+h.L.M.p.M.L L D.2.4 + 8 ^.=+P...j.V P v *.;.m..... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A .....m.;.*.v P V j...P.=+^.6 # l A ...M A o * - a {.)+m.o.,.;+n a e o t Y q m b 6 5 3 1 } _ ( ] ^ ' ; = * & $ $ ", +" . . . + @ @ # $ % & * > ] 0 m q +.++f.<.P ;+_.d.h ( { 1 :.F.S.X.i.F.}.I =+N. +4.O ! : }.I.N...N.m.D.#+w.h.N..... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A ..... .x.w.#+D.m.N... .Y.[._ @ l A ...M A o * = | -+,.A.*+H.q.[.:.f.D {.{.@.++h 6 5 4 2 } : ( { ^ ' , = * & $ # ", +" . . . @ @ # $ & * = > ] 0 m q +.B *.2.F =.-.{.o : < o @+w.A.x.p.1.f |.z n.N.Q.S i * > t 4.n.......P.N. .N....... .A l . . l A ... .A l $ l A ... .A l $ l A ... .A l . %.. l A .....s.j.N .P.......L.;.q - @ m A ...M A o = = ~ r -.r.o.S.D.Z.U '.U F.5.{.c.f 8 5 7 2 } < ( / ^ ' > - & & % # ", +" . . . + + @ $ % & * = , / b n p >+|.P @.].S T J r } b P .+S.O.I.T.g ! c R r. .s.y.}.1 % 5 _.Y.s.......P. +Q.n..... .A l . . l A ... .A m % m A ... .A m % m A ... .A l . %.. l A ...P.i.>.g.s.......N E.Q 3 @ @ m y ...M y r - = > 4 %+9.g.S.!+H.y.,+7.9.v.D w b 9 5 7 2 1 [ _ / ^ ' , - * & % $ ", +" . . . + + @ # $ % & * ; ' ( c r Y :.%+[.@.R S T T.r 7 ).H D.i.M.X ).] % ! t $.x.M h.~+Y ' ; n =.w.j.L n.i.7.T W.s. .L 7.k . . l 7.L .L 7.l % l 7.L .L 7.l % l 7.L .L 7.k . %.+ m A ... .'+Q 0.Y.X.N h.t.J j - @ m >.L .N >.o - = > ^ c 6.'.#+D.D.t.z ;.-.Q ).g 0 0 6 5 4 1 } : / ] ! ' ; = * & # ", +" . . . + + @ @ $ % & = > ' / 9 k s u >+B *.D E F !.l b B &+F.;.I -+5 ; % & 1 (.X A >.5.|.: # ! m 2.5.4.9.^.B &.0.7.A 7.^.b . . b #.7.A 7.#.c $ c #.7.A 7.#.c $ c #.7.A 7.^.b . Z + m A ... .z v s E X V I D j ' @ + # c S >.y >.S g ; - , ! ( c O E /.5.5.0.{+C t i c a 0 8 5 3 2 | < _ / ^ ' , - * & % ", +" . . . @ @ # % & * - , ! ] < 4 5 0 d g j m n r k 5 4 f r w s m 7 ! * & % ; } i r o k 5 ; + # > 2 f l j 0 ( { c m m m c ' ' c m m m c ) + ) c n m m c ) + ) c m m m c ' K @ m y ... .y r ~ 4 g k f 1 ; @ @ @ @ ~ e r r r g / - ; , ~ ] : 5 j w Y v Y e.l f c c c 0 0 9 5 4 1 } _ / ] ) ' ; = & % ", +" . . . + + @ # % * = - , ! ] / _ [ 1 1 4 3 3 3 4 4 1 [ < : ( / ^ ) > ; = = * * - = = = & $ $ $ % & & & & % # # % $ $ $ $ + + + + $ $ % % % @ @ # & & & & % @ @ @ $ $ $ $ $ + + . $ n y ... .y r * % * * * & % $ % $ % % - - ; ; , ; , ' ) ^ / _ } 2 5 8 0 b c c c d c c a 0 9 6 3 4 1 [ ( ] ^ ) ; = * & ", +" . . . + + @ # $ & & = , ' ~ ] ( : [ | 1 4 4 3 4 4 1 1 } < ( / ] ~ ' , ; ; - = * * & & & % % % % % % $ $ $ # # # @ @ @ + + + + + + @ @ @ @ # # # # $ $ $ # # # # @ @ @ + + + + + + % r y ... .z r = $ % % % % % % & & & & * * = = ; > , ) ~ { ( : [ 1 3 5 8 0 a c c d c c c a a 9 6 3 1 } _ ( ] ) , - * & ", +" . . . + @ # # $ & * - , ) ^ / ( : | 1 4 3 7 5 7 7 3 2 1 } < ( / ] ^ ! ) ' , , > > ; ; ; - - - - = = = * * * & % % % $ $ $ # # $ $ $ $ % % & & & * * * * * & & & % % $ $ # # # # # = r z ... .z s > = = = - - - - - ; ; ; > > , , ) ! ~ ^ / ( : [ 1 4 7 8 0 a c d d e e d d c a 9 8 7 1 } < ( ] ! ' - * * ", +" . . . . + @ $ % & * ; , ! ] ( : [ | 2 4 7 5 5 5 5 7 4 2 1 } : _ ( { ] ^ ~ ! ) ) ) ' ' ' ' ' ' ' , , , > > ; - - = = * * & & & & * * * = = - - ; ; ; ; ; ; ; - - = * * & & & & & & ; s z ... .z e.! > , , , ' ' ' , ' ' ' ) ) ! ! ^ ^ { ( ( : [ | 2 7 5 9 a b c e f f f f d c c a 9 5 4 1 < _ ] ~ ' ; * * ", +" . . + + @ # % * = > , ~ { ( : } 1 4 7 5 5 8 8 6 5 5 3 4 1 | [ : _ ( / / { ] ] ] ^ ^ ^ ^ ^ ^ ~ ~ ~ ! ) ) ' , , , > > ; ; ; ; ; ; ; > , , , , ' ' ' ' ' ' ' , , , > ; ; - - - - - ' w y L .N y q ] ! ! ~ ~ ^ ^ ^ ^ ^ ^ ^ ] ] { { / ( ( : < } 1 2 7 5 9 0 b d e f g g g g f e c b 0 6 3 2 } _ ( ] ' , - * ", +" . . + + @ # $ % & = > ' ~ { _ [ | 1 3 5 8 8 8 9 9 8 6 5 5 3 2 1 | } [ < : : _ _ ( ( ( ( ( ( ( ( ( / / { ] ] ^ ~ ! ! ) ' ' ' ' ' ' ) ) ! ~ ^ ^ ] ] ^ ^ ^ ] ^ ^ ~ ! ) ' , , > > > > ! k x z p.z /.n ( { / / ( ( ( ( ( ( ( ( ( _ : : < [ } } 1 2 4 7 6 9 0 b c d f g g h g g g e c b 0 8 3 1 } : / ^ ) , - * ", +" . . + + @ # $ & & - , ) ~ { _ [ 1 3 7 6 8 0 0 0 0 0 9 8 6 5 7 7 4 2 1 1 1 | | } } } } } } } [ [ < < : : _ ( ( / / { ] ] ^ ^ ^ ^ ^ ] { / ( / ( ( ( ( ( ( ( ( / / { ] ^ ~ ! ~ ! ! ~ ~ 1 n t Y u r 5 : _ : < [ [ } } } [ } } } | 1 1 1 1 2 4 7 5 5 9 0 a c c e f g g h i h g g e d c a 8 7 2 | < ( ] ! ' ; * ", +" . . + + @ # $ % * = , ) ~ / _ [ 1 3 5 6 0 0 0 b b b a 0 0 9 8 6 5 5 5 7 7 7 7 3 3 4 3 3 3 4 4 4 2 1 1 1 | } } < : : _ ( ( ( ( ( ( _ : : < [ } | } } } } } } < : : _ ( / / / { { / ( ( [ } } 1 1 | 1 1 1 1 2 4 4 3 3 3 3 3 3 7 3 7 7 5 6 6 9 0 0 a c c e g g h i j j i i h g f d c 0 8 5 4 1 < ( ] ! ' - * ", +" . . + + @ @ $ % * = , ' ^ / _ [ 2 3 5 8 0 a b c c c c c b b a a 0 0 0 9 9 9 9 9 8 8 9 9 8 8 8 6 5 6 5 5 7 3 4 2 1 1 | } | } } | } | 1 1 1 2 4 4 3 3 3 3 4 4 2 1 1 } [ [ : : _ _ : < [ [ | | 1 2 3 7 5 5 6 6 8 8 9 9 9 9 9 9 0 9 0 0 0 0 a b c c d e f g h i j j j j j i i g f e c a 0 5 4 1 [ ( ] ! ' - * ", +" . . + + @ @ $ % * = , ) ^ / _ } 2 7 5 8 0 b c d d e e e d d d c c c c c c c b c c c c b b b a b a 0 0 0 9 8 6 5 5 5 3 4 3 4 4 3 4 3 7 5 5 5 6 8 8 8 8 6 8 5 5 7 3 4 2 1 1 | | | | 1 1 2 4 3 5 5 6 9 0 0 0 a a b b c c b c c c c c c d d d e f g g h h i j j j k k j j j j g g e c b 8 5 3 1 [ ( ] ! ' - * ", +" . . + + @ # $ & * - , ) ^ / : | 1 7 5 9 0 c d e f f g g g g g f f g f g g f g g f f f f f f f f e e d c c b b a 0 0 9 8 6 8 8 6 8 9 9 0 0 0 a b b b b a a 0 0 8 6 5 5 7 3 4 4 4 4 3 7 5 6 8 9 0 a b c c d e f f f g g f g g g g g g h g h i i i j j j k k l l l l l k j j h f f c 0 9 5 4 | [ ( ] ) ' - * ", +" . . + + @ # $ & & - , ) ^ / : [ 2 7 5 0 0 c e f g g h h h i i h i i i i i i i i i i i i i j i i i h g g f f e d c c c b b b b b b c c d d d e f f e e e d d c c a 0 0 9 6 6 6 6 6 8 8 0 a a c c e f g g g h i i i j j j j j j j j j j j j k k k k l l m m m m l l m k j j g g e c 0 8 7 2 } : / ^ ) ' - * ", +" . . + + @ # $ % & = , ' ~ / _ [ 1 3 5 9 a c d g g h i j j j j j k k k k l l l l l m m m m l l l k k j j j j i h g g g g f e e f g g g g g h i i i i i h h g g f d d c b a 0 a a 0 b b c c e f g g i j j k k k l l l m m m m m m m m m m m m m m m m m n m m m m m k k j i g f c b 0 6 5 1 | _ ( ^ ) ' - & ", +" . . + + @ # % * = , , ^ { _ [ 1 4 5 9 a c e g h i j j k l l l m m m m m m m m n m m m m m n m m m m l m l k k j j j i j i i j i j j j k j k k k k k j j j i h g f f e d c d d c d e f g g h i j k k l m m m m n m n n m n n n n o n n n o n n n n n n n n m m m k k i h g e c a 0 5 7 2 [ : / ] ) , - * ", +" . . . . + @ $ % * * ; ' ~ ] ( < | 2 5 8 0 c d g h j j k l l m m n n n n o o o o o o r o o r r o o o o n m n n m m m l l l k k l l m l m m m m m m m m m m l k j j i i g g g g g g g g h i j k l l m m n n n o o r o r r r r r r r r r o o r r r o o o o m m m m k j j i g f d b 0 8 5 4 | : ( { ! ) , = * ", +" . . . + @ # # % & * - , ) ^ / _ } 2 5 8 0 b d f g i j l l m m m n o o o o o r r o r r r r r r r o o o o o o o n n m n n n m m n m m n n n n n n n n m m m m l l k j j j i i i i i j j j k k m m m m n o o o r r r r r r r r r r r r o o r o o o n n n m m m m k j j h g g e c a 9 5 3 1 [ : ( ] ! , ; = & ", +" . . . + + @ # $ & * - > ) ^ / _ < 1 3 5 9 b c e g h j l l m m m n n n o o o o o o o n o n n n n n n n n o n n n n o o o o n n o o o o n o n n n n n n n m m m m l k k k j j j j j k k l l m l m m m m m m n m n m n n n n o o o o n n n m n m m m m m m l k j j h h g f e c 0 9 8 7 2 1 < ( { ^ ) , - * & ", +" . . + + + @ $ % * = ; ' ! ] ( < | 2 7 8 0 b d f h i j k m m n m m n m m m m m n m m m m m m m m m m m n m n m n n o n o n n o n n n n n n n m n m m m m m m m l l l l l l l l l l l l l l m l m m m m m m m m m m m m m m m m m l m l m l m k k l k k j j j h g g e c b a 9 6 5 4 1 } : ( { ) ) ; = * & ", +" . . . @ # # % * * - , ' ^ ( : [ 1 3 5 8 0 c d g g j j k k l m l l m l l m k l l k k l l l k k l k l m l m m m m n m m n n m m m m m m m m l l m l l k l l l m l l l m l l l l l l l l m l m l k k l k k j k j k l j j j j j j j j j j j j i j i h h g g f f e c b b 0 9 5 7 4 1 } < ( ] ! ! ' - * * % ", +" . . . + + @ # $ & * = ; ) ! ^ ( : | 1 3 8 0 b c e g h i j j j j j k k k j i j j i h i h h h g i h i j i j j j j k k k k k k l k k l k j k j j j j j j j j j j k l k l l l l l l l k k k j k j j j i i i i h g g g h g g g h h h h g g g g g g g f e e d c c c b 0 0 9 6 7 4 1 | < < ( { ~ ) ' - = * & $ ", +" . . . + + + @ # $ * * - , ) ^ { ( [ | 4 5 6 0 b c f f g g i i i h h g g g g f e e e f d d d e d f e g f f g g g g i h i i i i j h g g g g g g g g g g h g h i i j k j k k l m k k j j j j h g g g g f e e e c d c d c c c d d d d d c c c c c b b c a 0 0 9 0 6 6 5 5 4 2 1 | < _ ( { ~ ) ) ; = * & % # ", +" . . . + + @ # $ & * * ; ' ! ] ( : [ 1 4 5 8 0 a c c d e g g f g e e d d c b a a a 0 0 0 0 0 0 0 a 0 b b c c c d c d e e e e e d d c c c c c c c d c c e g f h g h j j j j j j j j h h g f f d c b b a 0 0 0 0 0 0 9 9 9 9 0 0 0 0 0 9 9 0 8 8 8 9 5 5 6 5 5 7 3 2 1 | | < : _ / { ~ ! ' ; - * * % $ # ", +" . . . + + + @ # % & * = ; ) ~ ] ( _ } 1 3 5 9 9 a b c c d c c c c c 0 0 0 9 8 8 6 6 5 6 5 5 6 5 6 6 6 8 8 0 0 0 0 0 0 b b 0 0 0 0 0 0 9 9 9 9 9 9 a a b b c e d f g g h h h h g g e e c c b a 0 0 9 6 5 5 6 7 5 5 5 5 5 5 7 7 7 7 7 7 3 3 3 3 3 3 2 2 2 2 1 1 1 [ [ < _ _ / / ^ ~ ! ' ; = * * % $ $ # ", +" . . + + @ # $ % & * ; ' ) ^ ] ( : } 2 3 5 5 9 0 a 0 0 a 0 0 9 8 6 6 5 5 3 3 3 2 2 2 2 2 2 2 2 2 3 3 3 7 5 5 5 5 6 5 5 6 5 5 5 5 5 5 5 5 5 7 5 5 6 8 9 0 a c c e f g f f g d c c b a 0 9 8 5 5 7 3 4 2 2 2 1 1 1 1 1 1 1 1 1 1 1 | | | 1 1 | 1 } } [ [ [ : : _ ( / / { ^ ! ! ) , ; - * * % $ # @ @ ", +" . . . + + @ # $ $ & * * ; ' ) ] { ( : } 1 4 5 5 6 9 8 8 9 6 6 5 7 3 3 2 2 | 1 } [ [ [ } } } [ [ } [ } 1 1 | 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 2 2 4 7 5 5 6 9 a a b c c c c b a a 0 8 6 5 7 4 1 | | } [ [ [ < [ : : : : : : : : : : _ _ _ _ _ _ : _ _ ( ( { { { ] ~ ! ! ! ' , ; - * = & % $ # @ @ @ ", +" . . . + + + @ # % & * = ; ) ! ] { ( : } 1 2 4 7 7 5 5 7 7 4 4 1 1 | [ [ : _ _ ( ( / ( / / ( ( ( _ ( _ _ _ _ : : : : : : : : : : _ _ _ : : < [ [ | | 1 4 3 5 6 8 9 0 0 0 0 9 8 5 5 3 2 1 | | < < _ _ ( / / { / { { { { / / / / / / / { { { { { ] { ^ ~ ~ ! ! ! ! ) ' , ; - = * = * & % $ $ @ @ @ . ", +" . . . . . + @ # $ % * * - ; ' ! ] / ( < [ | 1 1 2 1 2 1 2 1 | [ [ : _ / / { { ] ^ ^ ~ ~ ~ ~ ~ ^ ^ ^ ] { / { / / { { { { { / / / / / / { / / / _ _ < [ } 1 4 3 7 5 5 5 5 5 5 7 3 4 1 } [ < _ ( / { ] { ~ ~ ! ~ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ) ) ) ' ) ' , > ; ; = = * = * & % $ $ # # @ + . + ", +" . . . . . @ @ # $ % & * = , ) ! ] { ( _ < < [ | | | [ < [ : ( / { { ^ ! ! ! ) ) ) ' ' ' ' ' ) ' ) ) ) ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ~ { { / _ _ < | | 1 1 4 3 3 4 1 1 | [ < _ ( { / ~ ! ! ! ) ) ' , , > > > > > > > > > > > > > > > > > ; ; ; ; - - - = = = * * & % % $ $ # @ @ @ + . . . ", +" . . + + + # # $ % & * - , ) ! ~ { / ( ( _ _ < : _ ( _ / { { ~ ! ! ) , > ; - - - = - = - - - ; ; ; ; > > ; > > > > > > ; ; ; ; > > , ' ) ! ! ^ { / ( _ < < [ | | | | [ < < _ ( { { ~ ! ) ' , ; ; ; - - - = = = = = = = = = = = = = = = = = * * * = = * * * & & % % $ $ # # @ @ + @ + . . . ", +" . . + + + @ # $ & * * - > ' ! ~ ] { { / / / / { { ] ^ ! ! ' ' ; - - * * = * * * * * * * * * = = = * * = = = = = = = * * * = = = - - ; > ' ) ) ~ ] { / ( _ _ _ _ _ _ ( { { ] ~ ! ' , ; - = = * * & * & & & & & & & & & & & & & & & & & & & & % % % % % $ $ $ $ # # # @ @ + @ + . + . . . ", +" . . . . . + @ @ # $ & * * - ; ' ) ! ! ~ ^ ] ] ^ ~ ! ) ) ' , ; - = * * * % % % % % % % % % % % % % % % & & & & & & & & & & & & & & & * * = - ; , ' ! ! ~ ] { { { { { { ] ~ ! ! ) , ; - * * & & & % % % $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ # # # # # # @ @ @ @ + @ + + . + . . . . ", +" . . . . . + @ @ # $ & * * = - ; ' ) ) ! ! ! ! ) ' ' > - = = = * & $ $ $ # # # # # # # # # # # # # # # $ $ $ $ $ $ $ $ $ $ $ $ $ % % & * = = = - > , ) ! ) ! ! ! ! ) ) ) , > - = * * & % % # # # # # @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ + + + + + + + . . . . . . . ", +" . . . . + @ @ # $ % & * * = - ; ; > > > > ; ; - = = = * & % $ # # @ @ @ @ @ + + + + + @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ # # $ $ % & & * * - ; ; > , ' ' ' ' , > ; ; = * * & % % $ # # @ @ @ + + + + + + + + + + + + + + + + + + + + + + + + + + + . . . . + . . . . . ", +" . . + . + @ @ $ $ % & & * * = = - - - - = = * * & & % # # # @ @ + + + + . . . . . . . + + + + + + + + + + + + + + + + + + @ @ # # $ % % & * * * = - - ; ; - - = * * * & % % $ # @ @ + + + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +" . . . + . + + @ # # $ % % & * * * * * * & * & % % $ $ # @ @ @ + + + . . . . . . . . . . . . . . . . . . . . . . . . . + + + + @ @ # # $ % % & * * = * * * * = * * & % % $ # # @ @ + + + + . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "}; diff --git a/vcl/qa/cppunit/graphicfilter/filters-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-test.cxx new file mode 100644 index 000000000..26f743cfa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/filters-test.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +#include +#include +#include + +using namespace ::com::sun::star; + +/* Implementation of Filters test */ + +class VclFiltersTest : + public test::FiltersTest, + public test::BootstrapFixture +{ + std::unique_ptr mpGraphicFilter; +public: + VclFiltersTest() : + BootstrapFixture(true, false), + mpGraphicFilter(new GraphicFilter(false)) + {} + + virtual bool load(const OUString &, + const OUString &rURL, const OUString &, + SfxFilterFlags, SotClipboardFormatId, unsigned int) override; + + void checkExportImport(const OUString& aFilterShortName); + + /** + * Ensure CVEs remain unbroken + */ + void testCVEs(); + + void testScaling(); + void testExportImport(); + + CPPUNIT_TEST_SUITE(VclFiltersTest); + CPPUNIT_TEST(testCVEs); + CPPUNIT_TEST(testScaling); + CPPUNIT_TEST(testExportImport); + CPPUNIT_TEST_SUITE_END(); +}; + +bool VclFiltersTest::load(const OUString &, + const OUString &rURL, const OUString &, + SfxFilterFlags, SotClipboardFormatId, unsigned int) +{ + SvFileStream aFileStream(rURL, StreamMode::READ); + Graphic aGraphic; + bool bRetval(ERRCODE_NONE == mpGraphicFilter->ImportGraphic(aGraphic, rURL, aFileStream)); + + if (!bRetval) + { + // if error occurred, we are done + return bRetval; + } + + // if not and we have an embedded Vector Graphic Data, trigger it's interpretation + // to check for error. Graphic with VectorGraphicData (Svg/Emf/Wmf) load without error + // as long as one of the three types gets detected. Thus, cycles like load/save in + // other format will work (what may be wanted). For the test framework it was indirectly + // intended to trigger an error when load in the sense of deep data interpretation fails, + // so we need to trigger this here + if (aGraphic.getVectorGraphicData()) + { + if (aGraphic.getVectorGraphicData()->getRange().isEmpty()) + { + // invalid file or file with no content + return false; + } + } + + return true; +} + +void VclFiltersTest::testScaling() +{ + for (BmpScaleFlag i = BmpScaleFlag::Default; i <= BmpScaleFlag::BiLinear; i = static_cast(static_cast(i) + 1)) + { + Bitmap aBitmap( Size( 413, 409 ), 24 ); + BitmapEx aBitmapEx( aBitmap ); + + fprintf( stderr, "scale with type %d\n", int( i ) ); + CPPUNIT_ASSERT( aBitmapEx.Scale( 0.1937046, 0.193154, i ) ); + Size aAfter( aBitmapEx.GetSizePixel() ); + fprintf( stderr, "size %ld, %ld\n", aAfter.Width(), aAfter.Height() ); + CPPUNIT_ASSERT( labs (aAfter.Height() - aAfter.Width()) <= 1 ); + } +} + +void VclFiltersTest::checkExportImport(const OUString& aFilterShortName) +{ + Bitmap aBitmap( Size( 100, 100 ), 24 ); + aBitmap.Erase(COL_WHITE); + + SvMemoryStream aStream; + aStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT ); + + css::uno::Sequence< css::beans::PropertyValue > aFilterData( 3 ); + aFilterData[ 0 ].Name = "Interlaced"; + aFilterData[ 0 ].Value <<= sal_Int32(0); + aFilterData[ 1 ].Name = "Compression"; + aFilterData[ 1 ].Value <<= sal_Int32(1); + aFilterData[ 2 ].Name = "Quality"; + aFilterData[ 2 ].Value <<= sal_Int32(90); + + sal_uInt16 aFilterType = mpGraphicFilter->GetExportFormatNumberForShortName(aFilterShortName); + mpGraphicFilter->ExportGraphic( aBitmap, OUString(), aStream, aFilterType, &aFilterData ); + + CPPUNIT_ASSERT(aStream.Tell() > 0); + + aStream.Seek( STREAM_SEEK_TO_BEGIN ); + + Graphic aLoadedGraphic; + mpGraphicFilter->ImportGraphic( aLoadedGraphic, OUString(), aStream ); + + BitmapEx aLoadedBitmapEx = aLoadedGraphic.GetBitmapEx(); + Size aSize = aLoadedBitmapEx.GetSizePixel(); + + CPPUNIT_ASSERT_EQUAL(100L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(100L, aSize.Height()); +} + +void VclFiltersTest::testExportImport() +{ + fprintf(stderr, "Check ExportImport JPG\n"); + checkExportImport("jpg"); + fprintf(stderr, "Check ExportImport PNG\n"); + checkExportImport("png"); + fprintf(stderr, "Check ExportImport BMP\n"); + checkExportImport("bmp"); +} + +void VclFiltersTest::testCVEs() +{ +#ifndef DISABLE_CVE_TESTS + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/wmf/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/emf/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/png/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/jpg/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/gif/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/bmp/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/xbm/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/xpm/")); + + testDir(OUString(), + m_directories.getURLFromSrc("/vcl/qa/cppunit/graphicfilter/data/svm/")); +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclFiltersTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx b/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx new file mode 100644 index 000000000..a5c0d9e95 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/JpegReaderTest.cxx @@ -0,0 +1,167 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include + +static OUString const gaDataUrl("/vcl/qa/cppunit/jpeg/data/"); + +class JpegReaderTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + + Graphic loadJPG(const OUString& aURL); + +public: + void testReadRGB(); + void testReadGray(); + void testReadCMYK(); + + CPPUNIT_TEST_SUITE(JpegReaderTest); + CPPUNIT_TEST(testReadRGB); + CPPUNIT_TEST(testReadGray); + CPPUNIT_TEST(testReadCMYK); + CPPUNIT_TEST_SUITE_END(); +}; + +static int deltaColor(BitmapColor aColor1, BitmapColor aColor2) +{ + int deltaR = std::abs(aColor1.GetRed() - aColor2.GetRed()); + int deltaG = std::abs(aColor1.GetGreen() - aColor2.GetGreen()); + int deltaB = std::abs(aColor1.GetBlue() - aColor2.GetBlue()); + + return std::max(std::max(deltaR, deltaG), deltaB); +} + +static bool checkRect(Bitmap& rBitmap, int aLayerNumber, long nAreaHeight, long nAreaWidth, Color aExpectedColor, int nMaxDelta) +{ + BitmapScopedWriteAccess pAccess(rBitmap); + + long nWidth = std::min(nAreaWidth, pAccess->Width()); + long nHeight = std::min(nAreaHeight, pAccess->Height()); + + long firstX = 0 + aLayerNumber; + long firstY = 0 + aLayerNumber; + + long lastX = nWidth - 1 - aLayerNumber; + long lastY = nHeight - 1 - aLayerNumber; + + int delta; + + for (long y = firstY; y <= lastY; y++) + { + Color aColorFirst = pAccess->GetPixel(y, firstX); + delta = deltaColor(aColorFirst, aExpectedColor); + if (delta > nMaxDelta) + return false; + + Color aColorLast = pAccess->GetPixel(y, lastX); + delta = deltaColor(aColorLast, aExpectedColor); + if (delta > nMaxDelta) + return false; + } + for (long x = firstX; x <= lastX; x++) + { + Color aColorFirst = pAccess->GetPixel(firstY, x); + delta = deltaColor(aColorFirst, aExpectedColor); + if (delta > nMaxDelta) + return false; + + Color aColorLast = pAccess->GetPixel(lastY, x); + delta = deltaColor(aColorLast, aExpectedColor); + if (delta > nMaxDelta) + return false; + } + return true; +} + +static int getNumberOfImageComponents(const Graphic& rGraphic) +{ + GfxLink aLink = rGraphic.GetGfxLink(); + SvMemoryStream aMemoryStream(const_cast(aLink.GetData()), aLink.GetDataSize(), + StreamMode::READ | StreamMode::WRITE); + GraphicDescriptor aDescriptor(aMemoryStream, nullptr); + CPPUNIT_ASSERT(aDescriptor.Detect(true)); + return aDescriptor.GetNumberOfImageComponents(); +} + +Graphic JpegReaderTest::loadJPG(const OUString& aURL) +{ + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aGraphic; +} + +void JpegReaderTest::testReadRGB() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestRGB.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + int nMaxDelta = 1; // still acceptable color error + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0xff, 0x00, 0x00), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0x00, 0xff, 0x00), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x00, 0x00, 0xff), nMaxDelta)); + + CPPUNIT_ASSERT_EQUAL(3, getNumberOfImageComponents(aGraphic)); +} + +void JpegReaderTest::testReadGray() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestGray.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + aBitmap.Convert(BmpConversion::N24Bit); // convert to 24bit so we don't need to deal with palette + + int nMaxDelta = 1; + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0x36, 0x36, 0x36), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0xb6, 0xb6, 0xb6), nMaxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x12, 0x12, 0x12), nMaxDelta)); + + CPPUNIT_ASSERT_EQUAL(1, getNumberOfImageComponents(aGraphic)); +} + +void JpegReaderTest::testReadCMYK() +{ + Graphic aGraphic = loadJPG(getFullUrl("JPEGTestCMYK.jpeg")); + Bitmap aBitmap = aGraphic.GetBitmapEx().GetBitmap(); + Size aSize = aBitmap.GetSizePixel(); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Width()); + CPPUNIT_ASSERT_EQUAL(12L, aSize.Height()); + + int maxDelta = 1; + CPPUNIT_ASSERT(checkRect(aBitmap, 0, 8, 8, Color(0xff, 0xff, 0xff), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 1, 8, 8, Color(0xff, 0x00, 0x00), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 2, 8, 8, Color(0x00, 0xff, 0x00), maxDelta)); + CPPUNIT_ASSERT(checkRect(aBitmap, 3, 8, 8, Color(0x00, 0x00, 0xff), maxDelta)); + + CPPUNIT_ASSERT_EQUAL(4, getNumberOfImageComponents(aGraphic)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(JpegReaderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx b/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx new file mode 100644 index 000000000..b4d9d2460 --- /dev/null +++ b/vcl/qa/cppunit/jpeg/JpegWriterTest.cxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include + +static OUString const gaDataUrl("/vcl/qa/cppunit/jpeg/data/"); + +class JpegWriterTest : public test::BootstrapFixtureBase +{ + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + + BitmapEx load(const OUString& aURL); + BitmapEx roundtripJPG(const BitmapEx& bitmap); + BitmapEx roundtripJPG(const OUString& aURL); + +public: + void testWrite8BitGrayscale(); + void testWrite8BitNonGrayscale(); + + CPPUNIT_TEST_SUITE(JpegWriterTest); + CPPUNIT_TEST(testWrite8BitGrayscale); + CPPUNIT_TEST(testWrite8BitNonGrayscale); + CPPUNIT_TEST_SUITE_END(); +}; + +BitmapEx JpegWriterTest::load(const OUString& aURL) +{ + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + SvFileStream aFileStream(aURL, StreamMode::READ); + ErrCode bResult = rFilter.ImportGraphic(aGraphic, aURL, aFileStream); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aGraphic.GetBitmapEx(); +} + +BitmapEx JpegWriterTest::roundtripJPG(const OUString& aURL) { return roundtripJPG(load(aURL)); } + +BitmapEx JpegWriterTest::roundtripJPG(const BitmapEx& bitmap) +{ + SvMemoryStream stream; + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + sal_uInt16 exportFormatJPG = rFilter.GetExportFormatNumberForShortName(JPG_SHORTNAME); + Graphic aExportGraphic(bitmap); + ErrCode bResult = rFilter.ExportGraphic(aExportGraphic, "memory", stream, exportFormatJPG); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + stream.Seek(0); + Graphic aImportGraphic; + sal_uInt16 importFormatJPG = rFilter.GetImportFormatNumberForShortName(JPG_SHORTNAME); + bResult = rFilter.ImportGraphic(aImportGraphic, "memory", stream, importFormatJPG); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + return aImportGraphic.GetBitmapEx(); +} + +void JpegWriterTest::testWrite8BitGrayscale() +{ + Bitmap bitmap = roundtripJPG(getFullUrl("8BitGrayscale.jpg")).GetBitmap(); + Bitmap::ScopedReadAccess access(bitmap); + const ScanlineFormat format = access->GetScanlineFormat(); + // Check that it's still 8bit grayscale. + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, format); + CPPUNIT_ASSERT(bitmap.HasGreyPalette8Bit()); + // Check that the content is valid. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, access->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(access->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + access->GetColor(access->Height() - 1, access->Width() - 1)); +} + +void JpegWriterTest::testWrite8BitNonGrayscale() +{ + Bitmap bitmap = roundtripJPG(getFullUrl("8BitNonGrayscale.gif")).GetBitmap(); + Bitmap::ScopedReadAccess access(bitmap); + const ScanlineFormat format = access->GetScanlineFormat(); + // Check that it's still 8bit grayscale. + CPPUNIT_ASSERT_EQUAL(ScanlineFormat::N8BitPal, format); + // The original image has grayscale palette, just with entries in a different order. + // Do not check for grayscale 8bit, the roundtrip apparently fixes that. What's important + // is the content. + CPPUNIT_ASSERT(bitmap.HasGreyPaletteAny()); + // CPPUNIT_ASSERT(bitmap.HasGreyPalette8Bit()); + // Check that the content is valid. + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(0, access->Width() - 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), access->GetColor(access->Height() - 1, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), + access->GetColor(access->Height() - 1, access->Width() - 1)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(JpegWriterTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg b/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg new file mode 100644 index 000000000..91541e4a8 Binary files /dev/null and b/vcl/qa/cppunit/jpeg/data/8BitGrayscale.jpg differ diff --git a/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif new file mode 100644 index 000000000..295310949 Binary files /dev/null and b/vcl/qa/cppunit/jpeg/data/8BitNonGrayscale.gif differ diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg new file mode 100644 index 000000000..81cca025e Binary files /dev/null and b/vcl/qa/cppunit/jpeg/data/JPEGTestCMYK.jpeg differ diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg new file mode 100644 index 000000000..014825f42 Binary files /dev/null and b/vcl/qa/cppunit/jpeg/data/JPEGTestGray.jpeg differ diff --git a/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg new file mode 100644 index 000000000..3cfe1dda2 Binary files /dev/null and b/vcl/qa/cppunit/jpeg/data/JPEGTestRGB.jpeg differ diff --git a/vcl/qa/cppunit/lifecycle.cxx b/vcl/qa/cppunit/lifecycle.cxx new file mode 100644 index 000000000..a4a3f5d9e --- /dev/null +++ b/vcl/qa/cppunit/lifecycle.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class LifecycleTest : public test::BootstrapFixture +{ + void testWidgets(vcl::Window *pParent); + +public: + LifecycleTest() : BootstrapFixture(true, false) {} + + void testCast(); + void testVirtualDevice(); + void testMultiDispose(); + void testIsolatedWidgets(); + void testParentedWidgets(); + void testChildDispose(); + void testPostDispose(); + void testFocus(); + void testLeakage(); + void testToolkit(); + + CPPUNIT_TEST_SUITE(LifecycleTest); + CPPUNIT_TEST(testCast); + CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testMultiDispose); + CPPUNIT_TEST(testIsolatedWidgets); + CPPUNIT_TEST(testParentedWidgets); + CPPUNIT_TEST(testChildDispose); + CPPUNIT_TEST(testPostDispose); + CPPUNIT_TEST(testFocus); + CPPUNIT_TEST(testLeakage); + CPPUNIT_TEST(testToolkit); + CPPUNIT_TEST_SUITE_END(); +}; + +// A compile time sanity check +void LifecycleTest::testCast() +{ + ScopedVclPtrInstance< PushButton > xButton( nullptr, 0 ); + ScopedVclPtr xWindow(xButton); + + ScopedVclPtrInstance< MetricField > xField( nullptr, 0 ); + ScopedVclPtr xSpin(xField); + ScopedVclPtr xEdit(xField); + +// the following line should NOT compile +// VclPtr xButton2(xWindow); +} + +void LifecycleTest::testVirtualDevice() +{ + VclPtr pVDev = VclPtr< VirtualDevice >::Create(); + ScopedVclPtrInstance< VirtualDevice > pVDev2; + VclPtrInstance pVDev3; + VclPtrInstance pVDev4(DeviceFormat::BITMASK); + CPPUNIT_ASSERT(!!pVDev && !!pVDev2 && !!pVDev3 && !!pVDev4); + pVDev.disposeAndClear(); + pVDev4.disposeAndClear(); +} + +void LifecycleTest::testMultiDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->disposeOnce(); + xWin->disposeOnce(); + xWin->disposeOnce(); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT_EQUAL(static_cast(0), xWin->GetChildCount()); +} + +void LifecycleTest::testWidgets(vcl::Window *pParent) +{ + { + ScopedVclPtrInstance< PushButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< OKButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< CancelButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< HelpButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + + // Some widgets really insist on adoption. + if (pParent) + { + { + ScopedVclPtrInstance< CheckBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< Edit > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< ComboBox > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + { + ScopedVclPtrInstance< RadioButton > aPtr( pParent ); + (void)aPtr; // silence unused variable warning + } + } +} + +void LifecycleTest::testIsolatedWidgets() +{ + testWidgets(nullptr); +} + +void LifecycleTest::testParentedWidgets() +{ + ScopedVclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + xWin->Show(); + testWidgets(xWin); +} + +namespace { + +class DisposableChild : public vcl::Window +{ +public: + explicit DisposableChild(vcl::Window *pParent) : vcl::Window(pParent) {} + virtual ~DisposableChild() override + { + disposeOnce(); + } +}; + +} + +void LifecycleTest::testChildDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + CPPUNIT_ASSERT(xWin.get() != nullptr); + VclPtrInstance< DisposableChild > xChild( xWin.get() ); + xWin->Show(); + xChild->disposeOnce(); + xWin->disposeOnce(); +} + +void LifecycleTest::testPostDispose() +{ + VclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + xWin->disposeOnce(); + + // check selected methods continue to work post-dispose + CPPUNIT_ASSERT(!xWin->GetParent()); + xWin->Show(); + CPPUNIT_ASSERT(!xWin->IsReallyShown()); + CPPUNIT_ASSERT(!xWin->IsEnabled()); + CPPUNIT_ASSERT(!xWin->IsInputEnabled()); + CPPUNIT_ASSERT(!xWin->GetChild(0)); + CPPUNIT_ASSERT(!xWin->GetWindow(GetWindowType::Parent)); +} + +namespace { + +class FocusCrashPostDispose : public TabControl +{ +public: + explicit FocusCrashPostDispose(vcl::Window *pParent) : + TabControl(pParent, 0) + { + } + virtual bool PreNotify( NotifyEvent& ) override + { + return false; + } + virtual bool EventNotify( NotifyEvent& ) override + { + return false; + } + virtual void GetFocus() override + { + CPPUNIT_FAIL("get focus"); + } + virtual void LoseFocus() override + { + CPPUNIT_FAIL("this should never be called"); + } +}; + +} + +void LifecycleTest::testFocus() +{ + ScopedVclPtrInstance xWin(nullptr, WB_APP|WB_STDWORK); + ScopedVclPtrInstance< FocusCrashPostDispose > xChild(xWin); + xWin->Show(); + xChild->GrabFocus(); + // process asynchronous ToTop + Scheduler::ProcessTaskScheduling(); + // FIXME: really awful to test focus issues without showing windows. + // CPPUNIT_ASSERT(xChild->HasFocus()); +} + +namespace { + +template +class LeakTestClass : public vcl_type +{ + bool &mrDeleted; +public: + template + LeakTestClass(bool &bDeleted, Arg &&... arg) : + vcl_type(std::forward(arg)...), + mrDeleted(bDeleted) + { + mrDeleted = false; + } + ~LeakTestClass() + { + mrDeleted = true; + } +}; + +class LeakTestObject +{ + bool mbDeleted; + VclPtr mxRef; + void *mpRef; + LeakTestObject() + : mbDeleted(false) + , mpRef(nullptr) + { + } +public: + template static LeakTestObject * + Create(Arg &&... arg) + { + LeakTestObject *pNew = new LeakTestObject(); + pNew->mxRef = VclPtr< LeakTestClass< vcl_type > >::Create( pNew->mbDeleted, + std::forward(arg)...); + pNew->mpRef = static_cast(static_cast(pNew->mxRef)); + return pNew; + } + const VclPtr& getRef() const { return mxRef; } + void disposeAndClear() + { + mxRef.disposeAndClear(); + } + void assertDeleted() + { + if (!mbDeleted) + { + OUStringBuffer aMsg = "Type '"; + vcl::Window *pWin = static_cast(mpRef); + aMsg.appendAscii(typeid(*pWin).name()); + aMsg.append("' not freed after dispose"); + CPPUNIT_FAIL(OUStringToOString(aMsg.makeStringAndClear(), + RTL_TEXTENCODING_UTF8).getStr()); + } + } +}; + +} + +void LifecycleTest::testLeakage() +{ + std::vector aObjects; + + // Create objects + aObjects.push_back(LeakTestObject::Create(nullptr, WB_APP|WB_STDWORK)); + VclPtr xParent = aObjects.back()->getRef(); + + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + aObjects.push_back(LeakTestObject::Create(xParent)); + + { // something that looks like a dialog + aObjects.push_back(LeakTestObject::Create(xParent,WB_CLIPCHILDREN|WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE|WB_SIZEABLE)); + VclPtr xDlgParent = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create(xDlgParent)); + VclPtr xVBox = aObjects.back()->getRef(); + aObjects.push_back(LeakTestObject::Create(xVBox)); + } + + aObjects.push_back(LeakTestObject::Create(xParent, "PrintProgressDialog", "vcl/ui/printprogressdialog.ui")); + xParent.clear(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->getRef()->Show(); + + for (auto i = aObjects.rbegin(); i != aObjects.rend(); ++i) + (*i)->disposeAndClear(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + (*i)->assertDeleted(); + + for (auto i = aObjects.begin(); i != aObjects.end(); ++i) + delete *i; +} + +void LifecycleTest::testToolkit() +{ + LeakTestObject *pVclWin = LeakTestObject::Create(nullptr, WB_APP|WB_STDWORK); + css::uno::Reference xWindow(pVclWin->getRef()->GetComponentInterface(), css::uno::UNO_QUERY); + CPPUNIT_ASSERT(xWindow.is()); + + // test UNO dispose + css::uno::Reference xWinComponent = xWindow; + CPPUNIT_ASSERT(xWinComponent.is()); + CPPUNIT_ASSERT(!pVclWin->getRef()->IsDisposed()); + xWinComponent->dispose(); + CPPUNIT_ASSERT(pVclWin->getRef()->IsDisposed()); + + // test UNO cleanup + xWinComponent.clear(); + xWindow.clear(); + pVclWin->disposeAndClear(); + pVclWin->assertDeleted(); + + delete pVclWin; +} + +CPPUNIT_TEST_SUITE_REGISTRATION(LifecycleTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/mnemonic.cxx b/vcl/qa/cppunit/mnemonic.cxx new file mode 100644 index 000000000..e870e1d29 --- /dev/null +++ b/vcl/qa/cppunit/mnemonic.cxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include + +class VclMnemonicTest : public test::BootstrapFixture +{ +public: + VclMnemonicTest() : BootstrapFixture(true, false) {} + + void testMnemonic(); + + CPPUNIT_TEST_SUITE(VclMnemonicTest); + CPPUNIT_TEST(testMnemonic); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclMnemonicTest::testMnemonic() +{ + MnemonicGenerator aGenerator; + + { + OUString sResult = aGenerator.CreateMnemonic(u"ßa"); + CPPUNIT_ASSERT_EQUAL(u'~', sResult[1]); + } + + { + const sal_Unicode TEST[] = { 0x4E00, 'b' }; + OUString sResult = aGenerator.CreateMnemonic(OUString(TEST, SAL_N_ELEMENTS(TEST))); + CPPUNIT_ASSERT_EQUAL(u'~', sResult[1]); + } + + { + const sal_Unicode TEST[] = { 0x4E00 }; + OUString sResult = aGenerator.CreateMnemonic(OUString(TEST, SAL_N_ELEMENTS(TEST))); + CPPUNIT_ASSERT_EQUAL(OUString("(~C)"), sResult.copy(sResult.getLength() - 4)); + } + +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclMnemonicTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx new file mode 100644 index 000000000..e99a35f67 --- /dev/null +++ b/vcl/qa/cppunit/outdev.cxx @@ -0,0 +1,291 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class VclOutdevTest : public test::BootstrapFixture +{ +public: + VclOutdevTest() : BootstrapFixture(true, false) {} + + void testVirtualDevice(); + void testUseAfterDispose(); + void testPrinterBackgroundColor(); + void testWindowBackgroundColor(); + void testGetReadableFontColorPrinter(); + void testGetReadableFontColorWindow(); + void testDrawTransformedBitmapEx(); + void testDrawTransformedBitmapExFlip(); + void testRTL(); + void testRTLGuard(); + + CPPUNIT_TEST_SUITE(VclOutdevTest); + CPPUNIT_TEST(testVirtualDevice); + CPPUNIT_TEST(testUseAfterDispose); + CPPUNIT_TEST(testPrinterBackgroundColor); + CPPUNIT_TEST(testWindowBackgroundColor); + CPPUNIT_TEST(testGetReadableFontColorPrinter); + CPPUNIT_TEST(testGetReadableFontColorWindow); + CPPUNIT_TEST(testDrawTransformedBitmapEx); + CPPUNIT_TEST(testDrawTransformedBitmapExFlip); + CPPUNIT_TEST(testRTL); + CPPUNIT_TEST(testRTLGuard); + CPPUNIT_TEST_SUITE_END(); +}; + +void VclOutdevTest::testGetReadableFontColorPrinter() +{ + ScopedVclPtrInstance pPrinter; + CPPUNIT_ASSERT_EQUAL(pPrinter->GetReadableFontColor(COL_WHITE, COL_WHITE), COL_BLACK); +} + +void VclOutdevTest::testGetReadableFontColorWindow() +{ + ScopedVclPtrInstance pWindow(nullptr, WB_APP | WB_STDWORK); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_WHITE, COL_BLACK), COL_WHITE); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_WHITE, COL_WHITE), COL_BLACK); + CPPUNIT_ASSERT_EQUAL(pWindow->GetReadableFontColor(COL_BLACK, COL_BLACK), COL_WHITE); +} + +void VclOutdevTest::testPrinterBackgroundColor() +{ + ScopedVclPtrInstance pPrinter; + CPPUNIT_ASSERT_EQUAL(pPrinter->GetBackgroundColor(), COL_WHITE); +} + +void VclOutdevTest::testWindowBackgroundColor() +{ + ScopedVclPtrInstance pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->SetBackground(Wallpaper(COL_WHITE)); + CPPUNIT_ASSERT_EQUAL(pWindow->GetBackgroundColor(), COL_WHITE); +} + +void VclOutdevTest::testVirtualDevice() +{ + ScopedVclPtrInstance< VirtualDevice > pVDev; + pVDev->SetOutputSizePixel(Size(32,32)); + pVDev->SetBackground(Wallpaper(COL_WHITE)); + + CPPUNIT_ASSERT_EQUAL(pVDev->GetBackgroundColor(), COL_WHITE); + + pVDev->Erase(); + pVDev->DrawPixel(Point(1,2),COL_BLUE); + pVDev->DrawPixel(Point(31,30),COL_RED); + + Size aSize = pVDev->GetOutputSizePixel(); + CPPUNIT_ASSERT_EQUAL(Size(32,32), aSize); + + Bitmap aBmp = pVDev->GetBitmap(Point(),aSize); + +#if 0 + OUString rFileName("/tmp/foo-unx.png"); + try { + vcl::PNGWriter aWriter( aBmp ); + SvFileStream sOutput( rFileName, StreamMode::WRITE ); + aWriter.Write( sOutput ); + sOutput.Close(); + } catch (...) { + SAL_WARN("vcl", "Error writing png to " << rFileName); + } +#endif + + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(0,0))); +#if !defined _WIN32 //TODO: various failures on Windows tinderboxes + CPPUNIT_ASSERT_EQUAL(COL_BLUE, pVDev->GetPixel(Point(1,2))); + CPPUNIT_ASSERT_EQUAL(COL_RED, pVDev->GetPixel(Point(31,30))); +#endif + CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(30,31))); + + // Gotcha: y and x swap for BitmapReadAccess: deep joy. + Bitmap::ScopedReadAccess pAcc(aBmp); + CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast(pAcc->GetPixel(0,0))); +#if !defined _WIN32 //TODO: various failures on Windows tinderboxes + CPPUNIT_ASSERT_EQUAL(COL_BLUE, static_cast(pAcc->GetPixel(2,1))); + CPPUNIT_ASSERT_EQUAL(COL_RED, static_cast(pAcc->GetPixel(30,31))); +#endif + CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast(pAcc->GetPixel(31,30))); + +#if 0 + VclPtr pWin = VclPtr::Create( (vcl::Window *)nullptr ); + CPPUNIT_ASSERT( pWin ); + OutputDevice *pOutDev = pWin.get(); +#endif +} + +void VclOutdevTest::testUseAfterDispose() +{ + // Create a virtual device, enable map mode then dispose it. + ScopedVclPtrInstance pVDev; + + pVDev->EnableMapMode(); + + pVDev->disposeOnce(); + + // Make sure that these don't crash after dispose. + pVDev->GetInverseViewTransformation(); + + pVDev->GetViewTransformation(); +} + +void VclOutdevTest::testDrawTransformedBitmapEx() +{ + // Create a virtual device, and connect a metafile to it. + // Also create a 16x16 bitmap. + ScopedVclPtrInstance pVDev; + Bitmap aBitmap(Size(16, 16), 24); + { + // Fill the top left quarter with black. + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(j, i, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + basegfx::B2DHomMatrix aMatrix; + aMatrix.scale(8, 8); + // Rotate 90 degrees clockwise, so the black part goes to the top right. + aMatrix.rotate(M_PI / 2); + GDIMetaFile aMtf; + aMtf.Record(pVDev.get()); + + // Draw the rotated bitmap on the vdev. + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aMtf.GetActionSize()); + MetaAction* pAction = aMtf.GetAction(0); + CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); + auto pBitmapAction = static_cast(pAction); + const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx(); + Size aTransformedSize = rBitmapEx.GetSizePixel(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 16x16 + // - Actual : 8x8 + // I.e. the bitmap before scaling was already scaled down, just because it was rotated. + CPPUNIT_ASSERT_EQUAL(Size(16, 16), aTransformedSize); + + aBitmap = rBitmapEx.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + for (int i = 0; i < 16; ++i) + { + for (int j = 0; j < 16; ++j) + { + BitmapColor aColor = pAccess->GetPixel(j, i); + Color aExpected = i >= 8 && j < 8 ? COL_BLACK : COL_WHITE; + std::stringstream ss; + ss << "Color is expected to be "; + ss << ((aExpected == COL_WHITE) ? "white" : "black"); + ss << ", is " << aColor.AsRGBHexString(); + ss << " (row " << j << ", col " << i << ")"; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: c[00000000] + // - Actual : c[ffffff00] + // - Color is expected to be black, is ffffff (row 0, col 8) + // i.e. the top right quarter of the image was not fully black, there was a white first + // row. + CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), aExpected, Color(aColor)); + } + } +} + +void VclOutdevTest::testDrawTransformedBitmapExFlip() +{ + // Create a virtual device, and connect a metafile to it. + // Also create a 16x16 bitmap. + ScopedVclPtrInstance pVDev; + Bitmap aBitmap(Size(16, 16), 24); + { + // Fill the top left quarter with black. + BitmapScopedWriteAccess pWriteAccess(aBitmap); + pWriteAccess->Erase(COL_WHITE); + for (int i = 0; i < 8; ++i) + { + for (int j = 0; j < 8; ++j) + { + pWriteAccess->SetPixel(j, i, COL_BLACK); + } + } + } + BitmapEx aBitmapEx(aBitmap); + basegfx::B2DHomMatrix aMatrix; + // Negative y scale: bitmap should be upside down, so the black part goes to the bottom left. + aMatrix.scale(8, -8); + // Rotate 90 degrees clockwise, so the black part goes back to the top left. + aMatrix.rotate(M_PI / 2); + GDIMetaFile aMtf; + aMtf.Record(pVDev.get()); + + // Draw the scaled and rotated bitmap on the vdev. + pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aMtf.GetActionSize()); + MetaAction* pAction = aMtf.GetAction(0); + CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType()); + auto pBitmapAction = static_cast(pAction); + const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx(); + + aBitmap = rBitmapEx.GetBitmap(); + Bitmap::ScopedReadAccess pAccess(aBitmap); + int nX = 8 * 0.25; + int nY = 8 * 0.25; + BitmapColor aColor = pAccess->GetPixel(nY, nX); + std::stringstream ss; + ss << "Color is expected to be black, is " << aColor.AsRGBHexString(); + ss << " (row " << nY << ", col " << nX << ")"; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: c[00000000] + // - Actual : c[ffffff00] + // - Color is expected to be black, is ffffff (row 2, col 2) + // i.e. the top left quarter of the image was not black, due to a missing flip. + CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), COL_BLACK, Color(aColor)); +} + +void VclOutdevTest::testRTL() +{ + ScopedVclPtrInstance pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->EnableRTL(); + vcl::RenderContext& rRenderContext = *pWindow; + vcl::BufferDevice pBuffer(pWindow, rRenderContext); + + // Without the accompanying fix in place, this test would have failed, because the RTL status + // from pWindow was not propagated to pBuffer. + CPPUNIT_ASSERT(pBuffer->IsRTLEnabled()); +} + +void VclOutdevTest::testRTLGuard() +{ + ScopedVclPtrInstance pWindow(nullptr, WB_APP | WB_STDWORK); + pWindow->EnableRTL(); + pWindow->RequestDoubleBuffering(true); + ImplFrameData* pFrameData = pWindow->ImplGetWindowImpl()->mpFrameData; + vcl::PaintBufferGuard aGuard(pFrameData, pWindow); + // Without the accompanying fix in place, this test would have failed, because the RTL status + // from pWindow was not propagated to aGuard. + CPPUNIT_ASSERT(aGuard.GetRenderContext()->IsRTLEnabled()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/pdfexport/data/6m-wide.odg b/vcl/qa/cppunit/pdfexport/data/6m-wide.odg new file mode 100644 index 000000000..49fb9bfff Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/6m-wide.odg differ diff --git a/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf new file mode 100644 index 000000000..af665fcba Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf differ diff --git a/vcl/qa/cppunit/pdfexport/data/forcepoint71.key b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key new file mode 100644 index 000000000..716fe5848 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/forcepoint71.key differ diff --git a/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp new file mode 100644 index 000000000..b6787aff6 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/link-wrong-page.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf new file mode 100644 index 000000000..739a80c47 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/pdf-image-resource-inline-xobject-ref.pdf differ diff --git a/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt b/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt new file mode 100644 index 000000000..b5737ae27 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/reduce-image.fodt @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + iVBORw0KGgoAAAANSUhEUgAAAKAAAACgCAYAAACLz2ctAAAABmJLR0QA/wD/AP+gvaeTAAAA + CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5AEVDCUTfvEVdAAAAYhJREFUeNrt3bEJwzAQ + htFckjLreP8Bso5bc2lTpBDG4kfkvQUE5uNUGEnV3TdIufsECBABggARIAgQAYIAESAIEAGC + ABEgCBABggARIAgQAYIAESAIEAGCABEgCBABggARIHx7phZ+vF9D13Id217WXW9dExBbMAgQ + AYIAESAIEAGCABEgCBABIkAQIAIEASJAECAChKnq6hfTR88gsKarz46YgNiCESAIEAGCABEg + CBABwlSx27FStzHxW+oPlgmILRgBggARIAgQAYIAESAIEAGCABEgCBABggARIAgQAYIAESAI + EAGCABEgCBABggARIAgQAYIAESACBAEiQBAgAgQBIkAQIAIEASJAECACBAEiQBAgi4u9mJ56 + oRsTEASIAEGACBABggARIAiQP1LdmR8So39Cjm0v6663rgmILRgEiABBgAgQBIgAQYAIEASI + ABEgCBABggARIAgQAcJUsTMhYAIiQAQIAkSAIEAECAJEgCBABAgCRIAgQAQIAkSAIEAECKd9 + AEYENxB/sygQAAAAAElFTkSuQmCC + + + + diff --git a/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt b/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt new file mode 100644 index 000000000..99ff22746 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/reduce-small-image.fodt @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMklEQVR42mP4//8/AyWYYXAZ + wHSK+z8pbOoaAJIgBWM1gFh/jxqAxwCKYmHgE9KAZSYAhK3Dgc2FxfUAAAAASUVORK5CYII= + + + + diff --git a/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt b/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt new file mode 100644 index 000000000..ecd779537 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/softhyphen_pdf.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105093.odp b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp new file mode 100644 index 000000000..82ce29cda Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf105093.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105461.odp b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp new file mode 100644 index 000000000..9c86a3bd7 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf105461.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf105954.odt b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt new file mode 100644 index 000000000..ba5c96de6 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf105954.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106059.odt b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt new file mode 100644 index 000000000..a2c180378 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106059.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106206.odt b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt new file mode 100644 index 000000000..3581157de Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106206.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106693.odt b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt new file mode 100644 index 000000000..a2c180378 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106693.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106702.odt b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt new file mode 100644 index 000000000..da3b7e814 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106702.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt new file mode 100644 index 000000000..d46c93dff Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106972-pdf17.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf106972.odt b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt new file mode 100644 index 000000000..3fa76c49f Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf106972.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107013.odt b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt new file mode 100644 index 000000000..644e65c6d Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf107013.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107018.odt b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt new file mode 100644 index 000000000..3bfc7b2d7 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf107018.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107089.odt b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt new file mode 100644 index 000000000..5aaaab944 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf107089.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf107868.odt b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt new file mode 100644 index 000000000..8309f4b87 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf107868.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf108963.odp b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp new file mode 100644 index 000000000..246c0c72a Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf108963.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf109143.odt b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt new file mode 100644 index 000000000..7d9afa378 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf109143.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf113143.odp b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp new file mode 100644 index 000000000..5f8a1b10e Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf113143.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt new file mode 100644 index 000000000..63fe82946 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf115117-1.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt new file mode 100644 index 000000000..c1e1f6d43 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf115117-2.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115262.ods b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods new file mode 100644 index 000000000..b401a74ce Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf115262.ods differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf115967.odt b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt new file mode 100644 index 000000000..39f4ce178 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf115967.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt new file mode 100644 index 000000000..caabc4987 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf118244_radioButtonGroup.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121615.odt b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt new file mode 100644 index 000000000..7d2a87cf0 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf121615.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf121962.odt b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt new file mode 100644 index 000000000..a831b1136 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf121962.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf128630.odp b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp new file mode 100644 index 000000000..d216504b7 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf128630.odp differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt new file mode 100644 index 000000000..7fecc55c6 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf66597-1.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt new file mode 100644 index 000000000..3d7b5e59c Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf66597-2.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt new file mode 100644 index 000000000..6db91fe81 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf66597-3.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt new file mode 100644 index 000000000..47c370004 Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf99680-2.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/tdf99680.odt b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt new file mode 100644 index 000000000..de12f9baa Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/tdf99680.odt differ diff --git a/vcl/qa/cppunit/pdfexport/data/toc-link.fodt b/vcl/qa/cppunit/pdfexport/data/toc-link.fodt new file mode 100644 index 000000000..ab29e88a4 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/toc-link.fodt @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table of Contents + + + + + + + + + Table of Contents + + Heading 11 + + + Heading 1 + + + diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx new file mode 100644 index 000000000..fe402b4ed --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx @@ -0,0 +1,2295 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +static std::ostream& operator<<(std::ostream& rStrm, const Color& rColor) +{ + rStrm << "Color: R:" << static_cast(rColor.GetRed()) + << " G:" << static_cast(rColor.GetGreen()) + << " B:" << static_cast(rColor.GetBlue()) + << " A:" << static_cast(rColor.GetTransparency()); + return rStrm; +} + +namespace +{ + +struct CloseDocument { + void operator ()(FPDF_DOCUMENT doc) { + if (doc != nullptr) { + FPDF_CloseDocument(doc); + } + } +}; + +using DocumentHolder = + std::unique_ptr::type, CloseDocument>; + +struct ClosePage { + void operator ()(FPDF_PAGE page) { + if (page != nullptr) { + FPDF_ClosePage(page); + } + } +}; + +using PageHolder = + std::unique_ptr::type, ClosePage>; + +/// Tests the PDF export filter. +class PdfExportTest : public test::BootstrapFixture, public unotest::MacrosTest +{ + uno::Reference mxComponent; + utl::TempFile maTempFile; + SvMemoryStream maMemory; + // Export the document as PDF, then parse it with PDFium. + DocumentHolder exportAndParse(const OUString& rURL, const utl::MediaDescriptor& rDescriptor); + std::shared_ptr mpPDFium; + +public: + PdfExportTest(); + virtual void setUp() override; + virtual void tearDown() override; + void saveAsPDF(const OUString& rFile); + void load(const OUString& rFile, vcl::filter::PDFDocument& rDocument); + /// Tests that a pdf image is roundtripped back to PDF as a vector format. + void testTdf106059(); + /// Tests that text highlight from Impress is not lost. + void testTdf105461(); + void testTdf107868(); + /// Tests that embedded video from Impress is not exported as a linked one. + void testTdf105093(); + /// Tests export of non-PDF images. + void testTdf106206(); + /// Tests export of PDF images without reference XObjects. + void testTdf106693(); + void testForcePoint71(); + void testTdf106972(); + void testTdf106972Pdf17(); + void testSofthyphenPos(); + void testTdf107013(); + void testTdf107018(); + void testTdf107089(); + void testTdf99680(); + void testTdf99680_2(); + void testTdf108963(); + void testTdf118244_radioButtonGroup(); + /// Test writing ToUnicode CMAP for LTR ligatures. + void testTdf115117_1(); + /// Text extracting LTR text with ligatures. + void testTdf115117_1a(); + /// Test writing ToUnicode CMAP for RTL ligatures. + void testTdf115117_2(); + /// Test extracting RTL text with ligatures. + void testTdf115117_2a(); + /// Test writing ToUnicode CMAP for doubly encoded glyphs. + void testTdf66597_1(); + /// Test writing ActualText for RTL many to one glyph to Unicode mapping. + void testTdf66597_2(); + /// Test writing ActualText for LTR many to one glyph to Unicode mapping. + void testTdf66597_3(); + void testTdf109143(); + void testTdf105954(); + void testTdf128630(); + void testTdf106702(); + void testTdf113143(); + void testTdf115262(); + void testTdf121962(); + void testTdf115967(); + void testTdf121615(); + void testTocLink(); + void testPdfImageResourceInlineXObjectRef(); + void testReduceSmallImage(); + void testReduceImage(); + void testLinkWrongPage(); + void testLargePage(); + void testVersion15(); + void testDefaultVersion(); + void testMultiPagePDF(); + + + CPPUNIT_TEST_SUITE(PdfExportTest); + CPPUNIT_TEST(testTdf106059); + CPPUNIT_TEST(testTdf105461); + CPPUNIT_TEST(testTdf107868); + CPPUNIT_TEST(testTdf105093); + CPPUNIT_TEST(testTdf106206); + CPPUNIT_TEST(testTdf106693); + CPPUNIT_TEST(testForcePoint71); + CPPUNIT_TEST(testTdf106972); + CPPUNIT_TEST(testTdf106972Pdf17); + CPPUNIT_TEST(testSofthyphenPos); + CPPUNIT_TEST(testTdf107013); + CPPUNIT_TEST(testTdf107018); + CPPUNIT_TEST(testTdf107089); + CPPUNIT_TEST(testTdf99680); + CPPUNIT_TEST(testTdf99680_2); + CPPUNIT_TEST(testTdf108963); + CPPUNIT_TEST(testTdf118244_radioButtonGroup); + CPPUNIT_TEST(testTdf115117_1); + CPPUNIT_TEST(testTdf115117_1a); + CPPUNIT_TEST(testTdf115117_2); + CPPUNIT_TEST(testTdf115117_2a); + CPPUNIT_TEST(testTdf66597_1); + CPPUNIT_TEST(testTdf66597_2); + CPPUNIT_TEST(testTdf66597_3); + CPPUNIT_TEST(testTdf109143); + CPPUNIT_TEST(testTdf105954); + CPPUNIT_TEST(testTdf128630); + CPPUNIT_TEST(testTdf106702); + CPPUNIT_TEST(testTdf113143); + CPPUNIT_TEST(testTdf115262); + CPPUNIT_TEST(testTdf121962); + CPPUNIT_TEST(testTdf115967); + CPPUNIT_TEST(testTdf121615); + CPPUNIT_TEST(testTocLink); + CPPUNIT_TEST(testPdfImageResourceInlineXObjectRef); + CPPUNIT_TEST(testReduceSmallImage); + CPPUNIT_TEST(testReduceImage); + CPPUNIT_TEST(testLinkWrongPage); + CPPUNIT_TEST(testLargePage); + CPPUNIT_TEST(testVersion15); + CPPUNIT_TEST(testDefaultVersion); + CPPUNIT_TEST(testMultiPagePDF); + CPPUNIT_TEST_SUITE_END(); +}; + +PdfExportTest::PdfExportTest() +{ + maTempFile.EnableKillingFile(); +} + +DocumentHolder PdfExportTest::exportAndParse(const OUString& rURL, const utl::MediaDescriptor& rDescriptor) +{ + // Import the bugdoc and export as PDF. + mxComponent = loadFromDesktop(rURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeToURL(maTempFile.GetURL(), rDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + return pPdfDocument; +} + +void PdfExportTest::setUp() +{ + test::BootstrapFixture::setUp(); + + mxDesktop.set(frame::Desktop::create(mxComponentContext)); + + mpPDFium = vcl::pdf::PDFiumLibrary::get(); +} + +void PdfExportTest::tearDown() +{ + if (mxComponent.is()) + mxComponent->dispose(); + + test::BootstrapFixture::tearDown(); +} + +char const DATA_DIRECTORY[] = "/vcl/qa/cppunit/pdfexport/data/"; + +void PdfExportTest::saveAsPDF(const OUString& rFile) +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + rFile; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); +} + +void PdfExportTest::load(const OUString& rFile, vcl::filter::PDFDocument& rDocument) +{ + saveAsPDF(rFile); + + // Parse the export result. + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(rDocument.Read(aStream)); +} + +void PdfExportTest::testTdf106059() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106059.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + // Explicitly enable the usage of the reference XObject markup. + uno::Sequence aFilterData( comphelper::InitPropertySequence({ + {"UseReferenceXObject", uno::Any(true) } + })); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Assert that the XObject in the page resources dictionary is a reference XObject. + std::vector aPages = aDocument.GetPages(); + // The document has one page. + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + // The page has one image. + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pReferenceXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pReferenceXObject); + // The image is a reference XObject. + // This dictionary key was missing, so the XObject wasn't a reference one. + CPPUNIT_ASSERT(pReferenceXObject->Lookup("Ref")); +} + +void PdfExportTest::testTdf106693() +{ + vcl::filter::PDFDocument aDocument; + load("tdf106693.odt", aDocument); + + // Assert that the XObject in the page resources dictionary is a form XObject. + std::vector aPages = aDocument.GetPages(); + // The document has one page. + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + // The page has one image. + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + // The image is a form XObject. + auto pSubtype = dynamic_cast(pXObject->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype->GetValue()); + // This failed: UseReferenceXObject was ignored and Ref was always created. + CPPUNIT_ASSERT(!pXObject->Lookup("Ref")); + + // Assert that the form object refers to an inner form object, not a + // bitmap. + auto pInnerResources = dynamic_cast(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pInnerResources); + auto pInnerXObjects = dynamic_cast(pInnerResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pInnerXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pInnerXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pInnerXObject = pInnerXObjects->LookupObject(pInnerXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pInnerXObject); + auto pInnerSubtype = dynamic_cast(pInnerXObject->Lookup("Subtype")); + CPPUNIT_ASSERT(pInnerSubtype); + // This failed: this was Image (bitmap), not Form (vector). + CPPUNIT_ASSERT_EQUAL(OString("Form"), pInnerSubtype->GetValue()); +} + +void PdfExportTest::testTdf105461() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf105461.odp"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Make sure there is a filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nYellowPathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_YELLOW) + ++nYellowPathCount; + } + + // This was 0, the page contained no yellow paths. + CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount); +} + +void PdfExportTest::testTdf107868() +{ + // No need to run it on Windows, since it would use GDI printing, and not trigger PDF export + // which is the intent of the test. +// FIXME: Why does this fail on macOS? +#if !defined MACOSX && !defined _WIN32 + + // Import the bugdoc and print to PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf107868.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + uno::Reference xPrintable(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xPrintable.is()); + uno::Sequence aOptions(comphelper::InitPropertySequence( + { + {"FileName", uno::makeAny(maTempFile.GetURL())}, + {"Wait", uno::makeAny(true)} + })); + xPrintable->print(aOptions); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + if (!pPdfDocument) + // Printing to PDF failed in a non-interesting way, e.g. CUPS is not + // running, there is no printer defined, etc. + return; + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Make sure there is no filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nWhitePathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_WHITE) + ++nWhitePathCount; + } + + // This was 4, the page contained 4 white paths at problematic positions. + CPPUNIT_ASSERT_EQUAL(0, nWhitePathCount); +#endif +} + +void PdfExportTest::testTdf105093() +{ + vcl::filter::PDFDocument aDocument; + load("tdf105093.odp", aDocument); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // Get page annotations. + auto pAnnots = dynamic_cast(aPages[0]->Lookup("Annots")); + CPPUNIT_ASSERT(pAnnots); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pAnnots->GetElements().size()); + auto pAnnotReference = dynamic_cast(pAnnots->GetElements()[0]); + CPPUNIT_ASSERT(pAnnotReference); + vcl::filter::PDFObjectElement* pAnnot = pAnnotReference->LookupObject(); + CPPUNIT_ASSERT(pAnnot); + CPPUNIT_ASSERT_EQUAL(OString("Annot"), static_cast(pAnnot->Lookup("Type"))->GetValue()); + + // Get the Action -> Rendition -> MediaClip -> FileSpec. + auto pAction = dynamic_cast(pAnnot->Lookup("A")); + CPPUNIT_ASSERT(pAction); + auto pRendition = dynamic_cast(pAction->LookupElement("R")); + CPPUNIT_ASSERT(pRendition); + auto pMediaClip = dynamic_cast(pRendition->LookupElement("C")); + CPPUNIT_ASSERT(pMediaClip); + auto pFileSpec = dynamic_cast(pMediaClip->LookupElement("D")); + CPPUNIT_ASSERT(pFileSpec); + // Make sure the filespec refers to an embedded file. + // This key was missing, the embedded video was handled as a linked one. + CPPUNIT_ASSERT(pFileSpec->LookupElement("EF")); +} + +void PdfExportTest::testTdf106206() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106206.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // The page has a stream. + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure there is an image reference there. + OString aImage("/Im"); + auto pStart = static_cast(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + auto it = std::search(pStart, pEnd, aImage.getStr(), aImage.getStr() + aImage.getLength()); + CPPUNIT_ASSERT(it != pEnd); + + // And also that it's not an invalid one. + OString aInvalidImage("/Im0"); + it = std::search(pStart, pEnd, aInvalidImage.getStr(), aInvalidImage.getStr() + aInvalidImage.getLength()); + // This failed, object #0 was referenced. + CPPUNIT_ASSERT(bool(it == pEnd)); +} + +void PdfExportTest::testTdf109143() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf109143.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // Get access to the only image on the only page. + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Make sure it's re-compressed. + auto pLength = dynamic_cast(pXObject->Lookup("Length")); + CPPUNIT_ASSERT(pLength); + int nLength = pLength->GetValue(); + // This failed: cropped TIFF-in-JPEG wasn't re-compressed, so crop was + // lost. Size was 59416, now is 11827. + CPPUNIT_ASSERT(nLength < 50000); +} + +void PdfExportTest::testTdf106972() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Get access to the only form object on the only page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the only image inside the form object. + auto pFormResources = dynamic_cast(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pFormResources); + auto pImages = dynamic_cast(pFormResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pImages); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pImages->GetItems().size()); + vcl::filter::PDFObjectElement* pImage = pImages->LookupObject(pImages->GetItems().begin()->first); + CPPUNIT_ASSERT(pImage); + + // Assert resources of the image. + auto pImageResources = dynamic_cast(pImage->Lookup("Resources")); + CPPUNIT_ASSERT(pImageResources); + // This failed: the PDF image had no Font resource. + CPPUNIT_ASSERT(pImageResources->LookupElement("Font")); +} + +void PdfExportTest::testTdf106972Pdf17() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106972-pdf17.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + // Get access to the only image on the only page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Assert that we now attempt to preserve the original PDF data, even if + // the original input was PDF >= 1.4. + CPPUNIT_ASSERT(pXObject->Lookup("Resources")); +} + +void PdfExportTest::testSofthyphenPos() +{ + // No need to run it on Windows, since it would use GDI printing, and not trigger PDF export + // which is the intent of the test. +// FIXME: Why does this fail on macOS? +#if !defined MACOSX && !defined _WIN32 + + // Import the bugdoc and print to PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "softhyphen_pdf.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + uno::Reference xPrintable(mxComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xPrintable.is()); + uno::Sequence aOptions(comphelper::InitPropertySequence( + { + {"FileName", uno::makeAny(maTempFile.GetURL())}, + {"Wait", uno::makeAny(true)} + })); + xPrintable->print(aOptions); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + if (aFile.bad() || !aMemory.GetSize()) + { + // Printing to PDF failed in a non-interesting way, e.g. CUPS is not + // running, there is no printer defined, etc. + return; + } + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // tdf#96892 incorrect fractional part of font size caused soft-hyphen to + // be positioned inside preceding text (incorrect = 11.1, correct = 11.05) + + // there are 3 texts currently, for line 1, soft-hyphen, line 2 + bool haveText(false); + + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(pPdfPageObject)); + haveText = true; + double const size(FPDFTextObj_GetFontSize(pPdfPageObject)); + CPPUNIT_ASSERT_DOUBLES_EQUAL(11.05, size, 1E-06); + } + + CPPUNIT_ASSERT(haveText); +#endif +} + +void PdfExportTest::testTdf107013() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107013.odt", aDocument); + + // Get access to the only image on the only page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + // This failed, the reference to the image was created, but not the image. + CPPUNIT_ASSERT(pXObject); +} + +void PdfExportTest::testTdf107018() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107018.odt", aDocument); + + // Get access to the only image on the only page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the form object inside the image. + auto pXObjectResources = dynamic_cast(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + // Get access to Resources -> Font -> F1 of the form. + auto pFormResources = dynamic_cast(pForm->Lookup("Resources")); + CPPUNIT_ASSERT(pFormResources); + auto pFonts = dynamic_cast(pFormResources->LookupElement("Font")); + CPPUNIT_ASSERT(pFonts); + auto pF1Ref = dynamic_cast(pFonts->LookupElement("F1")); + CPPUNIT_ASSERT(pF1Ref); + vcl::filter::PDFObjectElement* pF1 = pF1Ref->LookupObject(); + CPPUNIT_ASSERT(pF1); + + // Check that Foo -> Bar of the font is of type Pages. + auto pFontFoo = dynamic_cast(pF1->Lookup("Foo")); + CPPUNIT_ASSERT(pFontFoo); + auto pBar = dynamic_cast(pFontFoo->LookupElement("Bar")); + CPPUNIT_ASSERT(pBar); + vcl::filter::PDFObjectElement* pObject = pBar->LookupObject(); + CPPUNIT_ASSERT(pObject); + auto pName = dynamic_cast(pObject->Lookup("Type")); + CPPUNIT_ASSERT(pName); + // This was "XObject", reference in a nested dictionary wasn't updated when + // copying the page stream of a PDF image. + CPPUNIT_ASSERT_EQUAL(OString("Pages"), pName->GetValue()); +} + +void PdfExportTest::testTdf107089() +{ + vcl::filter::PDFDocument aDocument; + load("tdf107089.odt", aDocument); + + // Get access to the only image on the only page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + + // Get access to the form object inside the image. + auto pXObjectResources = dynamic_cast(pXObject->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + // Make sure 'Hello' is part of the form object's stream. + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + OString aHello("Hello"); + auto pStart = static_cast(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aHello.getStr(), aHello.getStr() + aHello.getLength()); + // This failed, 'Hello' was part only a mixed compressed/uncompressed stream, i.e. garbage. + CPPUNIT_ASSERT(it != pEnd); +} + +void PdfExportTest::testTdf99680() +{ + vcl::filter::PDFDocument aDocument; + load("tdf99680.odt", aDocument); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // The page 1 has a stream. + vcl::filter::PDFObjectElement* pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Uncompress it. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // tdf#130150 See infos in task - short: tdf#99680 was not the + // correct fix, so empty clip regions are valid - allow again in tests + // Make sure there are no empty clipping regions. + // OString aEmptyRegion("0 0 m h W* n"); + // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength()); + // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd); + + // Count save graphic state (q) and restore (Q) operators + // and ensure their amount is equal + auto pStart = static_cast(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + size_t nSaveCount = std::count(pStart, pEnd, 'q'); + size_t nRestoreCount = std::count(pStart, pEnd, 'Q'); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount); +} + +void PdfExportTest::testTdf99680_2() +{ + vcl::filter::PDFDocument aDocument; + load("tdf99680-2.odt", aDocument); + + // For each document page + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aPages.size()); + for (size_t nPageNr = 0; nPageNr < aPages.size(); nPageNr++) + { + // Get page contents and stream. + vcl::filter::PDFObjectElement* pContents = aPages[nPageNr]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + vcl::filter::PDFStreamElement* pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // tdf#130150 See infos in task - short: tdf#99680 was not the + // correct fix, so empty clip regions are valid - allow again in tests + // Make sure there are no empty clipping regions. + // OString aEmptyRegion("0 0 m h W* n"); + // auto it = std::search(pStart, pEnd, aEmptyRegion.getStr(), aEmptyRegion.getStr() + aEmptyRegion.getLength()); + // CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty clipping region detected!", it, pEnd); + + // Count save graphic state (q) and restore (Q) operators + // and ensure their amount is equal + auto pStart = static_cast(aUncompressed.GetData()); + const char* pEnd = pStart + aUncompressed.GetSize(); + size_t nSaveCount = std::count(pStart, pEnd, 'q'); + size_t nRestoreCount = std::count(pStart, pEnd, 'Q'); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Save/restore graphic state operators count mismatch!", nSaveCount, nRestoreCount); + } +} + +void PdfExportTest::testTdf108963() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf108963.odp"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // FIXME: strangely this fails on some Win systems after a pdfium update, expected: 793.7; actual: 793 +#if !defined _WIN32 + // Test page size (28x15.75 cm, was 1/100th mm off, tdf#112690) + // bad: MediaBox[0 0 793.672440944882 446.428346456693] + // good: MediaBox[0 0 793.700787401575 446.456692913386] + const double aWidth = FPDF_GetPageWidth(pPdfPage.get()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(793.7, aWidth, 0.01); + const double aHeight = FPDF_GetPageHeight(pPdfPage.get()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(446.46, aHeight, 0.01); + + // Make sure there is a filled rectangle inside. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nYellowPathCount = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPdfPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPdfPageObject) != FPDF_PAGEOBJ_PATH) + continue; + + unsigned int nRed = 0, nGreen = 0, nBlue = 0, nAlpha = 0; + FPDFPageObj_GetFillColor(pPdfPageObject, &nRed, &nGreen, &nBlue, &nAlpha); + if (Color(nRed, nGreen, nBlue) == COL_YELLOW) + { + ++nYellowPathCount; + // The path described a yellow rectangle, but it was not rotated. + int nSegments = FPDFPath_CountSegments(pPdfPageObject); + CPPUNIT_ASSERT_EQUAL(5, nSegments); + FPDF_PATHSEGMENT pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(pSegment)); + float fX = 0; + float fY = 0; + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(245395, static_cast(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(244261, static_cast(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 1); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(275102, static_cast(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(267618, static_cast(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 2); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(287518, static_cast(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(251829, static_cast(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 3); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(257839, static_cast(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(228472, static_cast(round(fY * 1000))); + CPPUNIT_ASSERT(!FPDFPathSegment_GetClose(pSegment)); + + pSegment = FPDFPath_GetPathSegment(pPdfPageObject, 4); + CPPUNIT_ASSERT_EQUAL(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(pSegment)); + FPDFPathSegment_GetPoint(pSegment, &fX, &fY); + CPPUNIT_ASSERT_EQUAL(245395, static_cast(round(fX * 1000))); + CPPUNIT_ASSERT_EQUAL(244261, static_cast(round(fY * 1000))); + CPPUNIT_ASSERT(FPDFPathSegment_GetClose(pSegment)); + } + } + + CPPUNIT_ASSERT_EQUAL(1, nYellowPathCount); +#endif +} + +void PdfExportTest::testTdf118244_radioButtonGroup() +{ + vcl::filter::PDFDocument aDocument; + load("tdf118244_radioButtonGroup.odt", aDocument); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // There are eight radio buttons. + auto pAnnots = dynamic_cast(aPages[0]->Lookup("Annots")); + CPPUNIT_ASSERT(pAnnots); + CPPUNIT_ASSERT_EQUAL_MESSAGE("# of radio buttons",static_cast(8), pAnnots->GetElements().size()); + + sal_uInt32 nRadioGroups = 0; + for ( const auto& aElement : aDocument.GetElements() ) + { + auto pObject = dynamic_cast(aElement.get()); + if ( !pObject ) + continue; + auto pType = dynamic_cast(pObject->Lookup("FT")); + if ( pType && pType->GetValue() == "Btn" ) + { + auto pKids = dynamic_cast(pObject->Lookup("Kids")); + if ( pKids ) + { + size_t expectedSize = 2; + ++nRadioGroups; + if ( nRadioGroups == 3 ) + expectedSize = 3; + CPPUNIT_ASSERT_EQUAL(expectedSize, pKids->GetElements().size()); + } + } + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("# of radio groups", sal_uInt32(3), nRadioGroups); +} + +// This requires Carlito font, if it is missing the test will most likely +// fail. +void PdfExportTest::testTdf115117_1() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf115117-1.odt", aDocument); + + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + + // Get access to ToUnicode of the first font + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pToUnicodeRef = dynamic_cast(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + // The first values, <01> <02> etc., are glyph ids, they might change order + // if we changed how font subsets are created. + // The second values, <00740069> etc., are Unicode code points in hex, + // <00740069> is U+0074 and U+0069 i.e. "ti" which is a ligature in + // Carlito/Calibri. This test is failing if any of the second values + // changed which means we are not detecting ligatures and writing CMAP + // entries for them correctly. If glyph order in the subset changes then + // the order here will changes and the PDF has to be carefully inspected to + // ensure that the new values are correct before updating the string below. + OString aCmap("9 beginbfchar\n" + "<01> <00740069>\n" + "<02> <0020>\n" + "<03> <0074>\n" + "<04> <0065>\n" + "<05> <0073>\n" + "<06> <00660069>\n" + "<07> <0066006C>\n" + "<08> <006600660069>\n" + "<09> <00660066006C>\n" + "endbfchar"); + auto pStart = static_cast(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aCmap.getStr(), aCmap.getStr() + aCmap.getLength()); + CPPUNIT_ASSERT(it != pEnd); +#endif +} + +// This requires DejaVu Sans font, if it is missing the test will most likely +// fail. +void PdfExportTest::testTdf115117_2() +{ +#if HAVE_MORE_FONTS + // See the comments in testTdf115117_1() for explanation. + + vcl::filter::PDFDocument aDocument; + load("tdf115117-2.odt", aDocument); + + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pToUnicodeRef = dynamic_cast(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + OString aCmap("7 beginbfchar\n" + "<01> <06440627>\n" + "<02> <0020>\n" + "<03> <0641>\n" + "<04> <0642>\n" + "<05> <0648>\n" + "<06> <06440627>\n" + "<07> <0628>\n" + "endbfchar"); + auto pStart = static_cast(aObjectStream.GetData()); + const char* pEnd = pStart + aObjectStream.GetSize(); + auto it = std::search(pStart, pEnd, aCmap.getStr(), aCmap.getStr() + aCmap.getLength()); + CPPUNIT_ASSERT(it != pEnd); +#endif +} + +void PdfExportTest::testTdf115117_1a() +{ +#if HAVE_MORE_FONTS + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115117-1.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + auto pPdfTextPage = FPDFText_LoadPage(pPdfPage.get()); + CPPUNIT_ASSERT(pPdfTextPage); + + // Extract the text from the page. This pdfium API is a bit higher level + // than we want and might apply heuristic that give false positive, but it + // is a good approximation in addition to the check in testTdf115117_1(). + int nChars = FPDFText_CountChars(pPdfTextPage); + CPPUNIT_ASSERT_EQUAL(44, nChars); + + OUString aExpectedText = "ti ti test ti\r\nti test fi fl ffi ffl test fi"; + std::vector aChars(nChars); + for (int i = 0; i < nChars; i++) + aChars[i] = FPDFText_GetUnicode(pPdfTextPage, i); + OUString aActualText(aChars.data(), aChars.size()); + CPPUNIT_ASSERT_EQUAL(aExpectedText, aActualText); + + FPDFText_ClosePage(pPdfTextPage); +#endif +} + +void PdfExportTest::testTdf115117_2a() +{ +#if HAVE_MORE_FONTS + // See the comments in testTdf115117_1a() for explanation. + + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115117-2.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument(FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + auto pPdfTextPage = FPDFText_LoadPage(pPdfPage.get()); + CPPUNIT_ASSERT(pPdfTextPage); + + int nChars = FPDFText_CountChars(pPdfTextPage); + CPPUNIT_ASSERT_EQUAL(13, nChars); + + OUString aExpectedText = u"\u0627\u0644 \u0628\u0627\u0644 \u0648\u0642\u0641 \u0627\u0644"; + std::vector aChars(nChars); + for (int i = 0; i < nChars; i++) + aChars[i] = FPDFText_GetUnicode(pPdfTextPage, i); + OUString aActualText(aChars.data(), aChars.size()); + CPPUNIT_ASSERT_EQUAL(aExpectedText, aActualText); + + FPDFText_ClosePage(pPdfTextPage); +#endif +} + +void PdfExportTest::testTdf66597_1() +{ +#if HAVE_MORE_FONTS + // This requires Amiri font, if it is missing the test will fail. + vcl::filter::PDFDocument aDocument; + load("tdf66597-1.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("Amiri-Regular"), aName); + + auto pToUnicodeRef = dynamic_cast(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + // The <01> is glyph id, <0020> is code point. + // The document has three characters , but the font + // reuses the same glyph for space and nbspace so we should have a single + // CMAP entry for the space, and nbspace will be handled with ActualText + // (tested above). + std::string aCmap("1 beginbfchar\n" + "<01> <0020>\n" + "endbfchar"); + std::string aData(static_cast(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::string aActualText("/Span<(1), nCount); + + aActualText = "/Span<>>"; + nPos = aData.find(aActualText); + CPPUNIT_ASSERT_MESSAGE("ActualText not found!", nPos != std::string::npos); + } +#endif +} + +// This requires Reem Kufi font, if it is missing the test will fail. +void PdfExportTest::testTdf66597_2() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf66597-2.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("ReemKufi-Regular"), aName); + + auto pToUnicodeRef = dynamic_cast(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + std::string aCmap("8 beginbfchar\n" + "<02> <0632>\n" + "<03> <0020>\n" + "<04> <0648>\n" + "<05> <0647>\n" + "<06> <062F>\n" + "<08> <062C>\n" + "<09> <0628>\n" + "<0B> <0623>\n" + "endbfchar"); + std::string aData(static_cast(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::vector aCodes({ "0632", "062C", "0628", "0623" }); + std::string aActualText("/Span<>>"; + nPos = aData.find(aActualText); + CPPUNIT_ASSERT_MESSAGE("ActualText not found for " + aCode, nPos != std::string::npos); + } + } +#endif +} + +// This requires Gentium Basic font, if it is missing the test will fail. +void PdfExportTest::testTdf66597_3() +{ +#if HAVE_MORE_FONTS + vcl::filter::PDFDocument aDocument; + load("tdf66597-3.odt", aDocument); + + { + // Get access to ToUnicode of the first font + vcl::filter::PDFObjectElement* pToUnicode = nullptr; + for (const auto& aElement : aDocument.GetElements()) + { + auto pObject = dynamic_cast(aElement.get()); + if (!pObject) + continue; + auto pType = dynamic_cast(pObject->Lookup("Type")); + if (pType && pType->GetValue() == "Font") + { + auto pName = dynamic_cast(pObject->Lookup("BaseFont")); + auto aName = pName->GetValue().copy(7); // skip the subset id + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected font name", OString("GentiumBasic"), aName); + + auto pToUnicodeRef = dynamic_cast(pObject->Lookup("ToUnicode")); + CPPUNIT_ASSERT(pToUnicodeRef); + pToUnicode = pToUnicodeRef->LookupObject(); + break; + } + } + + CPPUNIT_ASSERT(pToUnicode); + auto pStream = pToUnicode->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream aObjectStream; + ZCodec aZCodec; + aZCodec.BeginCompression(); + pStream->GetMemory().Seek(0); + aZCodec.Decompress(pStream->GetMemory(), aObjectStream); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + aObjectStream.Seek(0); + std::string aCmap("2 beginbfchar\n" + "<01> <1ECB0331030B>\n" + "<05> <0020>\n" + "endbfchar"); + std::string aData(static_cast(aObjectStream.GetData()), aObjectStream.GetSize()); + auto nPos = aData.find(aCmap); + CPPUNIT_ASSERT(nPos != std::string::npos); + } + + { + auto aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + // Get page contents and stream. + auto pContents = aPages[0]->LookupObject("Contents"); + CPPUNIT_ASSERT(pContents); + auto pStream = pContents->GetStream(); + CPPUNIT_ASSERT(pStream); + auto& rObjectStream = pStream->GetMemory(); + + // Uncompress the stream. + SvMemoryStream aUncompressed; + ZCodec aZCodec; + aZCodec.BeginCompression(); + rObjectStream.Seek(0); + aZCodec.Decompress(rObjectStream, aUncompressed); + CPPUNIT_ASSERT(aZCodec.EndCompression()); + + // Make sure the expected ActualText is present. + std::string aData(static_cast(aUncompressed.GetData()), aUncompressed.GetSize()); + + std::string aActualText("/Span<>>"); + size_t nCount = 0; + size_t nPos = 0; + while ((nPos = aData.find(aActualText, nPos)) != std::string::npos) + { + nCount++; + nPos += aActualText.length(); + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of ActualText entries does not match!", static_cast(4), nCount); + } +#endif +} + +void PdfExportTest::testTdf105954() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf105954.odt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + uno::Sequence aFilterData(comphelper::InitPropertySequence( + { { "ReduceImageResolution", uno::Any(true) }, + { "MaxImageResolution", uno::Any(static_cast(300)) } })); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result with pdfium. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + SvMemoryStream aMemory; + aMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(aMemory.GetData(), aMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // There is a single image on the page. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, nPageObjectCount); + + // Check width of the image. + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), /*index=*/0); + FPDF_IMAGEOBJ_METADATA aMeta; + CPPUNIT_ASSERT(FPDFImageObj_GetImageMetadata(pPageObject, pPdfPage.get(), &aMeta)); + // This was 2000, i.e. the 'reduce to 300 DPI' request was ignored. + // This is now around 238 (228 on macOS). + CPPUNIT_ASSERT_LESS(static_cast(250), aMeta.width); +} + +void PdfExportTest::testTdf128630() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf128630.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has one page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Assert the aspect ratio of the only bitmap on the page. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // assertion failed + // - Expression: nWidth != nHeight + // i.e. the bitmap lost its custom aspect ratio during export. + CPPUNIT_ASSERT(nWidth != nHeight); + } +} + +void PdfExportTest::testTdf106702() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf106702.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has two pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First page already has the correct image position. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nExpected = 0; + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nExpected = fTop; + break; + } + + // Second page had an incorrect image position. + pPdfPage.reset(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nActual = 0; + nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nActual = fTop; + break; + } + + // This failed, vertical pos is 818 points, was 1674 (outside visible page + // bounds). + CPPUNIT_ASSERT_EQUAL(nExpected, nActual); +} + +void PdfExportTest::testTdf113143() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf113143.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + uno::Sequence aFilterData(comphelper::InitPropertySequence({ + { "ExportNotesPages", uno::Any(true) }, + // ReduceImageResolution is on by default and that hides the bug we + // want to test. + { "ReduceImageResolution", uno::Any(false) }, + // Set a custom PDF version. + { "SelectPdfVersion", uno::makeAny(static_cast(16)) }, + })); + aMediaDescriptor["FilterData"] <<= aFilterData; + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has two pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First has the original (larger) image. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nLarger = 0; + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nLarger = fRight - fLeft; + break; + } + + // Second page has the scaled (smaller) image. + pPdfPage.reset(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage.get()); + int nSmaller = 0; + nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_IMAGE) + continue; + + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + nSmaller = fRight - fLeft; + break; + } + + // This failed, both were 319, now nSmaller is 169. + CPPUNIT_ASSERT_LESS(nLarger, nSmaller); + + // The following check used to fail in the past, header was "%PDF-1.5": + maMemory.Seek(0); + OString aExpectedHeader("%PDF-1.6"); + OString aHeader(read_uInt8s_ToOString(maMemory, aExpectedHeader.getLength())); + CPPUNIT_ASSERT_EQUAL(aExpectedHeader, aHeader); +} + +void PdfExportTest::testForcePoint71() +{ + // I just care it doesn't crash + saveAsPDF("forcepoint71.key"); +} + +void PdfExportTest::testTdf115262() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115262.ods"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("calc_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(8, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the 6th page. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/5)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Look up the position of the first image and the 400th row. + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + int nFirstImageTop = 0; + int nRowTop = 0; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + float fLeft = 0, fBottom = 0, fRight = 0, fTop = 0; + FPDFPageObj_GetBounds(pPageObject, &fLeft, &fBottom, &fRight, &fTop); + + if (FPDFPageObj_GetType(pPageObject) == FPDF_PAGEOBJ_IMAGE) + { + nFirstImageTop = fTop; + } + else if (FPDFPageObj_GetType(pPageObject) == FPDF_PAGEOBJ_TEXT) + { + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 0); + std::vector aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sText(aText.data(), nTextSize / 2 - 1); + if (sText == "400") + nRowTop = fTop; + } + } + // Make sure that the top of the "400" is below the top of the image (in + // bottom-right-corner-based PDF coordinates). + // This was: expected less than 144, actual is 199. + CPPUNIT_ASSERT_LESS(nFirstImageTop, nRowTop); + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf121962() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf121962.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the first page + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + + // Make sure the table sum is displayed as "0", not faulty expression. + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_TEXT) + continue; + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 0); + std::vector aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sText(aText.data(), nTextSize / 2 - 1); + CPPUNIT_ASSERT(sText != "** Expression is faulty **"); + } + + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf115967() +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf115967.odt"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + auto pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Get the first page + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + FPDF_TEXTPAGE pTextPage = FPDFText_LoadPage(pPdfPage.get()); + + // Make sure the elements inside a formula in a RTL document are exported + // LTR ( m=750abc ) and not RTL ( m=057cba ) + int nPageObjectCount = FPDFPage_CountObjects(pPdfPage.get()); + OUString sText; + for (int i = 0; i < nPageObjectCount; ++i) + { + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), i); + if (FPDFPageObj_GetType(pPageObject) != FPDF_PAGEOBJ_TEXT) + continue; + unsigned long nTextSize = FPDFTextObj_GetText(pPageObject, pTextPage, nullptr, 2); + std::vector aText(nTextSize); + FPDFTextObj_GetText(pPageObject, pTextPage, aText.data(), nTextSize); + OUString sChar(aText.data(), nTextSize / 2 - 1); + sText += sChar.trim(); + } + CPPUNIT_ASSERT_EQUAL(OUString("m=750abc"), sText); + + FPDFText_ClosePage(pTextPage); +} + +void PdfExportTest::testTdf121615() +{ + vcl::filter::PDFDocument aDocument; + load("tdf121615.odt", aDocument); + + // The document has one page. + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(1), aPages.size()); + + // Get access to the only image on the only page. + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + CPPUNIT_ASSERT_EQUAL(static_cast(1), pXObjects->GetItems().size()); + vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first); + CPPUNIT_ASSERT(pXObject); + vcl::filter::PDFStreamElement* pStream = pXObject->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + + // Load the embedded image. + rObjectStream.Seek( 0 ); + GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + sal_uInt16 format; + ErrCode bResult = rFilter.ImportGraphic(aGraphic, OUString( "import" ), rObjectStream, + GRFILTER_FORMAT_DONTKNOW, &format); + CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, bResult); + + // The image should be grayscale 8bit JPEG. + sal_uInt16 jpegFormat = rFilter.GetImportFormatNumberForShortName( JPG_SHORTNAME ); + CPPUNIT_ASSERT( jpegFormat != GRFILTER_FORMAT_NOTFOUND ); + CPPUNIT_ASSERT_EQUAL( jpegFormat, format ); + BitmapEx aBitmap = aGraphic.GetBitmapEx(); + CPPUNIT_ASSERT_EQUAL( 200L, aBitmap.GetSizePixel().Width()); + CPPUNIT_ASSERT_EQUAL( 300L, aBitmap.GetSizePixel().Height()); + CPPUNIT_ASSERT_EQUAL( 8, int(aBitmap.GetBitCount())); + // tdf#121615 was caused by broken handling of data width with 8bit color, + // so the test image has some black in the bottomright corner, check it's there + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 0, 0 )); + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 0, 299 )); + CPPUNIT_ASSERT_EQUAL( COL_WHITE, aBitmap.GetPixelColor( 199, 0 )); + CPPUNIT_ASSERT_EQUAL( COL_BLACK, aBitmap.GetPixelColor( 199, 299 )); +} + +void PdfExportTest::testTocLink() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "toc-link.fodt"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + // Update the ToC. + uno::Reference xDocumentIndexesSupplier(mxComponent, + uno::UNO_QUERY); + CPPUNIT_ASSERT(xDocumentIndexesSupplier.is()); + + uno::Reference xToc( + xDocumentIndexesSupplier->getDocumentIndexes()->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT(xToc.is()); + + xToc->refresh(); + + // Save as PDF. + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Ensure there is a link on the first page (in the ToC). + int nStartPos = 0; + FPDF_LINK pLinkAnnot = nullptr; + // Without the accompanying fix in place, this test would have failed, as FPDFLink_Enumerate() + // returned false, as the page contained no links. + CPPUNIT_ASSERT(FPDFLink_Enumerate(pPdfPage.get(), &nStartPos, &pLinkAnnot)); +} + +void PdfExportTest::testReduceSmallImage() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reduce-small-image.fodt"; + mxComponent = loadFromDesktop(aURL); + + // Save as PDF. + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the PDF: get the image. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pPageObject)); + + // Make sure we don't scale down a tiny bitmap. + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 16 + // - Actual : 6 + // i.e. the image was scaled down to 300 DPI, even if it had tiny size. + CPPUNIT_ASSERT_EQUAL(16, nWidth); + CPPUNIT_ASSERT_EQUAL(16, nHeight); +} + +void PdfExportTest::testReduceImage() +{ + // Load the Writer document. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reduce-image.fodt"; + mxComponent = loadFromDesktop(aURL); + + // Save as PDF. + uno::Reference xFactory = getMultiServiceFactory(); + uno::Reference xFilter( + xFactory->createInstance("com.sun.star.document.PDFFilter"), uno::UNO_QUERY); + uno::Reference xExporter(xFilter, uno::UNO_QUERY); + xExporter->setSourceDocument(mxComponent); + + SvFileStream aOutputStream(maTempFile.GetURL(), StreamMode::WRITE); + uno::Reference xOutputStream(new utl::OStreamWrapper(aOutputStream)); + + uno::Sequence aFilterData( + comphelper::InitPropertySequence({ { "ReduceImageResolution", uno::Any(false) } })); + + // This is intentionally in an "unlucky" order, output stream comes before filter data. + uno::Sequence aDescriptor(comphelper::InitPropertySequence({ + { "FilterName", uno::Any(OUString("writer_pdf_Export")) }, + { "OutputStream", uno::Any(xOutputStream) }, + { "FilterData", uno::Any(aFilterData) }, + })); + xFilter->filter(aDescriptor); + aOutputStream.Close(); + + // Parse the PDF: get the image. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pPageObject)); + + // Make sure we don't scale down a bitmap. + FPDF_BITMAP pBitmap = FPDFImageObj_GetBitmap(pPageObject); + CPPUNIT_ASSERT(pBitmap); + int nWidth = FPDFBitmap_GetWidth(pBitmap); + int nHeight = FPDFBitmap_GetHeight(pBitmap); + FPDFBitmap_Destroy(pBitmap); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 160 + // - Actual : 6 + // i.e. the image was scaled down even with ReduceImageResolution=false. + CPPUNIT_ASSERT_EQUAL(160, nWidth); + CPPUNIT_ASSERT_EQUAL(160, nHeight); +} + +bool HasLinksOnPage(PageHolder& pPdfPage) +{ + int nStartPos = 0; + FPDF_LINK pLinkAnnot = nullptr; + return FPDFLink_Enumerate(pPdfPage.get(), &nStartPos, &pLinkAnnot); +} + +void PdfExportTest::testLinkWrongPage() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "link-wrong-page.odp"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("impress_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has 2 pages. + CPPUNIT_ASSERT_EQUAL(2, FPDF_GetPageCount(pPdfDocument.get())); + + // First page should have 1 link (2nd slide, 1st was hidden). + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + + // Without the accompanying fix in place, this test would have failed, as the link of the first + // page went to the second page due to the hidden first slide. + CPPUNIT_ASSERT(HasLinksOnPage(pPdfPage)); + + // Second page should have no links (3rd slide). + PageHolder pPdfPage2(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/1)); + CPPUNIT_ASSERT(pPdfPage2.get()); + CPPUNIT_ASSERT(!HasLinksOnPage(pPdfPage2)); +} + +void PdfExportTest::testLargePage() +{ + // Import the bugdoc and export as PDF. + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "6m-wide.odg"; + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("draw_pdf_Export"); + DocumentHolder pPdfDocument = exportAndParse(aURL, aMediaDescriptor); + + // The document has 1 page. + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Check the value (not the unit) of the page size. + FS_SIZEF aSize; + FPDF_GetPageSizeByIndexF(pPdfDocument.get(), 0, &aSize); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 8503.94 + // - Actual : 17007.875 + // i.e. the value for 600 cm was larger than the 14 400 limit set in the spec. + CPPUNIT_ASSERT_DOUBLES_EQUAL(8503.94, static_cast(aSize.width), 0.01); +} + +void PdfExportTest::testPdfImageResourceInlineXObjectRef() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference xText = xTextDocument->getText(); + uno::Reference xCursor = xText->createTextCursor(); + + // Insert the PDF image. + uno::Reference xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference xGraphicObject( + xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + OUString aURL + = m_directories.getURLFromSrc(DATA_DIRECTORY) + "pdf-image-resource-inline-xobject-ref.pdf"; + xGraphicObject->setPropertyValue("GraphicURL", uno::makeAny(aURL)); + uno::Reference xShape(xGraphicObject, uno::UNO_QUERY); + xShape->setSize(awt::Size(1000, 1000)); + uno::Reference xTextContent(xGraphicObject, uno::UNO_QUERY); + xText->insertTextContent(xCursor->getStart(), xTextContent, /*bAbsorb=*/false); + + // Save as PDF. + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDF_GetPageCount(pPdfDocument.get())); + + // Make sure that the page -> form -> form has a child image. + PageHolder pPdfPage(FPDF_LoadPage(pPdfDocument.get(), /*page_index=*/0)); + CPPUNIT_ASSERT(pPdfPage.get()); + CPPUNIT_ASSERT_EQUAL(1, FPDFPage_CountObjects(pPdfPage.get())); + FPDF_PAGEOBJECT pPageObject = FPDFPage_GetObject(pPdfPage.get(), 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pPageObject)); + // 2: white background and the actual object. + CPPUNIT_ASSERT_EQUAL(2, FPDFFormObj_CountObjects(pPageObject)); + FPDF_PAGEOBJECT pFormObject = FPDFFormObj_GetObject(pPageObject, 1); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pFormObject)); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. the sub-form was missing its image. + CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pFormObject)); + + // Check if the inner form object (original page object in the pdf image) has the correct + // rotation. + FPDF_PAGEOBJECT pInnerFormObject = FPDFFormObj_GetObject(pFormObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(pInnerFormObject)); + CPPUNIT_ASSERT_EQUAL(1, FPDFFormObj_CountObjects(pInnerFormObject)); + FPDF_PAGEOBJECT pImage = FPDFFormObj_GetObject(pInnerFormObject, 0); + CPPUNIT_ASSERT_EQUAL(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(pImage)); + FS_MATRIX aMatrix; + FPDFFormObj_GetMatrix(pInnerFormObject, &aMatrix); + basegfx::B2DHomMatrix aMat{ aMatrix.a, aMatrix.c, aMatrix.e, aMatrix.b, aMatrix.d, aMatrix.f }; + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate = 0; + double fShearX = 0; + aMat.decompose(aScale, aTranslate, fRotate, fShearX); + int nRotateDeg = basegfx::rad2deg(fRotate); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: -90 + // - Actual : 0 + // i.e. rotation was lost on pdf export. + CPPUNIT_ASSERT_EQUAL(-90, nRotateDeg); +} + +void PdfExportTest::testDefaultVersion() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + + // Save as PDF. + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + int nFileVersion = 0; + FPDF_GetFileVersion(pPdfDocument.get(), &nFileVersion); + CPPUNIT_ASSERT_EQUAL(16, nFileVersion); +} + +void PdfExportTest::testVersion15() +{ + // Create an empty document. + mxComponent = loadFromDesktop("private:factory/swriter"); + CPPUNIT_ASSERT(mxComponent.is()); + + // Save as PDF. + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence aFilterData(comphelper::InitPropertySequence( + { { "SelectPdfVersion", uno::makeAny(static_cast(15)) } })); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + aMediaDescriptor["FilterData"] <<= aFilterData; + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ); + maMemory.WriteStream(aFile); + DocumentHolder pPdfDocument( + FPDF_LoadMemDocument(maMemory.GetData(), maMemory.GetSize(), /*password=*/nullptr)); + CPPUNIT_ASSERT(pPdfDocument.get()); + int nFileVersion = 0; + FPDF_GetFileVersion(pPdfDocument.get(), &nFileVersion); + CPPUNIT_ASSERT_EQUAL(15, nFileVersion); +} + +// Check round-trip of importing and exporting the PDF with PDFium filter, +// which imports the PDF document as multiple PDFs as graphic object. +// Each page in the document has one PDF graphic object which content is +// the corresponding page in the PDF. When such a document is exported, +// the PDF graphic gets embedded into the exported PDF document (as a +// Form XObject). +void PdfExportTest::testMultiPagePDF() +{ +// setenv only works on unix based systems +#ifndef _WIN32 + // We need to enable PDFium import (and make sure to disable after the test) + bool bResetEnvVar = false; + if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr) + { + bResetEnvVar = true; + setenv("LO_IMPORT_USE_PDFIUM", "1", false); + } + comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() { + if (bResetEnvVar) + unsetenv("LO_IMPORT_USE_PDFIUM"); + }); + + // Load the PDF and save as PDF + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf"; + mxComponent = loadFromDesktop(aURL); + CPPUNIT_ASSERT(mxComponent.is()); + + uno::Reference xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export"); + xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + // Parse the export result. + vcl::filter::PDFDocument aDocument; + SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ); + CPPUNIT_ASSERT(aDocument.Read(aStream)); + + std::vector aPages = aDocument.GetPages(); + CPPUNIT_ASSERT_EQUAL(static_cast(3), aPages.size()); + + vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources"); + CPPUNIT_ASSERT(pResources); + + auto pXObjects = dynamic_cast(pResources->Lookup("XObject")); + CPPUNIT_ASSERT(pXObjects); + + CPPUNIT_ASSERT_EQUAL(static_cast(3), pXObjects->GetItems().size()); // 3 PDFs as Form XObjects + + std::vector rIDs; + for (auto const & rPair : pXObjects->GetItems()) { + rIDs.push_back(rPair.first); + } + + // Let's check the embedded PDF pages - just make sure the size differs, + // which should indicate we don't have 3 times the same page. + + { // embedded PDF page 1 + vcl::filter::PDFObjectElement* pXObject1 = pXObjects->LookupObject(rIDs[0]); + CPPUNIT_ASSERT(pXObject1); + CPPUNIT_ASSERT_EQUAL(OString("Im19"), rIDs[0]); + + auto pSubtype1 = dynamic_cast(pXObject1->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype1); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype1->GetValue()); + + auto pXObjectResources = dynamic_cast(pXObject1->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected. + CPPUNIT_ASSERT_EQUAL(sal_uInt64(230), rObjectStream.remainingSize()); + } + + { // embedded PDF page 2 + vcl::filter::PDFObjectElement* pXObject2 = pXObjects->LookupObject(rIDs[1]); + CPPUNIT_ASSERT(pXObject2); + CPPUNIT_ASSERT_EQUAL(OString("Im34"), rIDs[1]); + + auto pSubtype2 = dynamic_cast(pXObject2->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype2); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype2->GetValue()); + + auto pXObjectResources = dynamic_cast(pXObject2->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected + CPPUNIT_ASSERT_EQUAL(sal_uInt64(309), rObjectStream.remainingSize()); + } + + { // embedded PDF page 3 + vcl::filter::PDFObjectElement* pXObject3 = pXObjects->LookupObject(rIDs[2]); + CPPUNIT_ASSERT(pXObject3); + CPPUNIT_ASSERT_EQUAL(OString("Im4"), rIDs[2]); + + auto pSubtype3 = dynamic_cast(pXObject3->Lookup("Subtype")); + CPPUNIT_ASSERT(pSubtype3); + CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype3->GetValue()); + + auto pXObjectResources = dynamic_cast(pXObject3->Lookup("Resources")); + CPPUNIT_ASSERT(pXObjectResources); + auto pXObjectForms = dynamic_cast(pXObjectResources->LookupElement("XObject")); + CPPUNIT_ASSERT(pXObjectForms); + vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first); + CPPUNIT_ASSERT(pForm); + + vcl::filter::PDFStreamElement* pStream = pForm->GetStream(); + CPPUNIT_ASSERT(pStream); + SvMemoryStream& rObjectStream = pStream->GetMemory(); + rObjectStream.Seek(STREAM_SEEK_TO_BEGIN); + + // Just check that the size of the page stream is what is expected + CPPUNIT_ASSERT_EQUAL(sal_uInt64(193), rObjectStream.remainingSize()); + } +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/png/PngFilterTest.cxx b/vcl/qa/cppunit/png/PngFilterTest.cxx new file mode 100644 index 000000000..c304ee9d3 --- /dev/null +++ b/vcl/qa/cppunit/png/PngFilterTest.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +using namespace css; + +class PngFilterTest : public test::BootstrapFixture +{ + OUString maDataUrl; + + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(maDataUrl) + sFileName; + } + +public: + PngFilterTest() + : BootstrapFixture(true, false) + , maDataUrl("/vcl/qa/cppunit/png/data/") + { + } + + void testPng(); + + CPPUNIT_TEST_SUITE(PngFilterTest); + CPPUNIT_TEST(testPng); + CPPUNIT_TEST_SUITE_END(); +}; + +void PngFilterTest::testPng() +{ + for (const OUString& aFileName : { OUString("rect-1bit-pal.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + + if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x00, 0x00), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } + for (const OUString& aFileName : + { OUString("color-rect-8bit-RGB.png"), OUString("color-rect-4bit-pal.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + if (pAccess->GetBitCount() == 24 || pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } + for (const OUString& aFileName : { OUString("alpha-rect-8bit-RGBA.png") }) + { + SvFileStream aFileStream(getFullUrl(aFileName), StreamMode::READ); + + vcl::PngImageReader aPngReader(aFileStream); + BitmapEx aBitmapEx; + aPngReader.read(aBitmapEx); + + Bitmap aBitmap = aBitmapEx.GetBitmap(); + { + Bitmap::ScopedReadAccess pAccess(aBitmap); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAccess->Height()); + + if (pAccess->GetBitCount() == 24) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x00), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x00), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0x00), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0x00), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x00), pAccess->GetPixel(2, 2)); + + AlphaMask aAlpha = aBitmapEx.GetAlpha(); + { + AlphaMask::ScopedReadAccess pAlphaAccess(aAlpha); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(8), pAlphaAccess->GetBitCount()); + CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Width()); + CPPUNIT_ASSERT_EQUAL(4L, pAlphaAccess->Height()); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x80, 0x00), + pAlphaAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), + pAlphaAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), + pAlphaAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xC0, 0x00), + pAlphaAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0x40, 0x00), + pAlphaAccess->GetPixel(2, 2)); + } + } + else if (pAccess->GetBitCount() == 32) + { + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 3)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(3, 0)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0xFF, 0x80), pAccess->GetPixel(0, 3)); + + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0x00, 0x00, 0x40), pAccess->GetPixel(1, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0xFF, 0x00, 0xC0), pAccess->GetPixel(1, 2)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0x00, 0x00, 0xFF, 0xC0), pAccess->GetPixel(2, 1)); + CPPUNIT_ASSERT_EQUAL(BitmapColor(0xFF, 0xFF, 0x00, 0x40), pAccess->GetPixel(2, 2)); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Bitmap is not 24 or 32 bit.", false); + } + } + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(PngFilterTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png b/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png new file mode 100644 index 000000000..1e90e1a6c Binary files /dev/null and b/vcl/qa/cppunit/png/data/alpha-rect-8bit-RGBA.png differ diff --git a/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png new file mode 100644 index 000000000..740eede51 Binary files /dev/null and b/vcl/qa/cppunit/png/data/color-rect-4bit-pal.png differ diff --git a/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png new file mode 100644 index 000000000..727859d8a Binary files /dev/null and b/vcl/qa/cppunit/png/data/color-rect-8bit-RGB.png differ diff --git a/vcl/qa/cppunit/png/data/rect-1bit-pal.png b/vcl/qa/cppunit/png/data/rect-1bit-pal.png new file mode 100644 index 000000000..cf7ac3e7c Binary files /dev/null and b/vcl/qa/cppunit/png/data/rect-1bit-pal.png differ diff --git a/vcl/qa/cppunit/svm/data/arc.svm b/vcl/qa/cppunit/svm/data/arc.svm new file mode 100644 index 000000000..5d443a704 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/arc.svm differ diff --git a/vcl/qa/cppunit/svm/data/bitmapexs.svm b/vcl/qa/cppunit/svm/data/bitmapexs.svm new file mode 100644 index 000000000..f6860bdff Binary files /dev/null and b/vcl/qa/cppunit/svm/data/bitmapexs.svm differ diff --git a/vcl/qa/cppunit/svm/data/bitmaps.svm b/vcl/qa/cppunit/svm/data/bitmaps.svm new file mode 100644 index 000000000..bf42f1bae Binary files /dev/null and b/vcl/qa/cppunit/svm/data/bitmaps.svm differ diff --git a/vcl/qa/cppunit/svm/data/chord.svm b/vcl/qa/cppunit/svm/data/chord.svm new file mode 100644 index 000000000..7c7136eed Binary files /dev/null and b/vcl/qa/cppunit/svm/data/chord.svm differ diff --git a/vcl/qa/cppunit/svm/data/clipregion.svm b/vcl/qa/cppunit/svm/data/clipregion.svm new file mode 100644 index 000000000..aa0d277fe Binary files /dev/null and b/vcl/qa/cppunit/svm/data/clipregion.svm differ diff --git a/vcl/qa/cppunit/svm/data/ellipse.svm b/vcl/qa/cppunit/svm/data/ellipse.svm new file mode 100644 index 000000000..369e4292c Binary files /dev/null and b/vcl/qa/cppunit/svm/data/ellipse.svm differ diff --git a/vcl/qa/cppunit/svm/data/fillcolor.svm b/vcl/qa/cppunit/svm/data/fillcolor.svm new file mode 100644 index 000000000..8e1a826c4 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/fillcolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/gradient.svm b/vcl/qa/cppunit/svm/data/gradient.svm new file mode 100644 index 000000000..68811e065 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/gradient.svm differ diff --git a/vcl/qa/cppunit/svm/data/hatch.svm b/vcl/qa/cppunit/svm/data/hatch.svm new file mode 100644 index 000000000..4e6bdf638 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/hatch.svm differ diff --git a/vcl/qa/cppunit/svm/data/line.svm b/vcl/qa/cppunit/svm/data/line.svm new file mode 100644 index 000000000..67441ec92 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/line.svm differ diff --git a/vcl/qa/cppunit/svm/data/linecolor.svm b/vcl/qa/cppunit/svm/data/linecolor.svm new file mode 100644 index 000000000..2cba7f734 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/linecolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/masks.svm b/vcl/qa/cppunit/svm/data/masks.svm new file mode 100644 index 000000000..b9e777930 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/masks.svm differ diff --git a/vcl/qa/cppunit/svm/data/overlinecolor.svm b/vcl/qa/cppunit/svm/data/overlinecolor.svm new file mode 100644 index 000000000..10cd773fb Binary files /dev/null and b/vcl/qa/cppunit/svm/data/overlinecolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/pie.svm b/vcl/qa/cppunit/svm/data/pie.svm new file mode 100644 index 000000000..1eaf67447 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/pie.svm differ diff --git a/vcl/qa/cppunit/svm/data/pixel.svm b/vcl/qa/cppunit/svm/data/pixel.svm new file mode 100644 index 000000000..dc15ab8f0 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/pixel.svm differ diff --git a/vcl/qa/cppunit/svm/data/point.svm b/vcl/qa/cppunit/svm/data/point.svm new file mode 100644 index 000000000..5b5c3731b Binary files /dev/null and b/vcl/qa/cppunit/svm/data/point.svm differ diff --git a/vcl/qa/cppunit/svm/data/polygon.svm b/vcl/qa/cppunit/svm/data/polygon.svm new file mode 100644 index 000000000..162ccfd9c Binary files /dev/null and b/vcl/qa/cppunit/svm/data/polygon.svm differ diff --git a/vcl/qa/cppunit/svm/data/polyline.svm b/vcl/qa/cppunit/svm/data/polyline.svm new file mode 100644 index 000000000..9139da371 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/polyline.svm differ diff --git a/vcl/qa/cppunit/svm/data/polypolygon.svm b/vcl/qa/cppunit/svm/data/polypolygon.svm new file mode 100644 index 000000000..ea01bd14a Binary files /dev/null and b/vcl/qa/cppunit/svm/data/polypolygon.svm differ diff --git a/vcl/qa/cppunit/svm/data/pushpop.svm b/vcl/qa/cppunit/svm/data/pushpop.svm new file mode 100644 index 000000000..d5ab6e80a Binary files /dev/null and b/vcl/qa/cppunit/svm/data/pushpop.svm differ diff --git a/vcl/qa/cppunit/svm/data/rasterop.svm b/vcl/qa/cppunit/svm/data/rasterop.svm new file mode 100644 index 000000000..ac9f796c2 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/rasterop.svm differ diff --git a/vcl/qa/cppunit/svm/data/rect.svm b/vcl/qa/cppunit/svm/data/rect.svm new file mode 100644 index 000000000..8c398b572 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/rect.svm differ diff --git a/vcl/qa/cppunit/svm/data/roundrect.svm b/vcl/qa/cppunit/svm/data/roundrect.svm new file mode 100644 index 000000000..aa0ca3e29 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/roundrect.svm differ diff --git a/vcl/qa/cppunit/svm/data/strecthtext.svm b/vcl/qa/cppunit/svm/data/strecthtext.svm new file mode 100644 index 000000000..f6dcb5fba Binary files /dev/null and b/vcl/qa/cppunit/svm/data/strecthtext.svm differ diff --git a/vcl/qa/cppunit/svm/data/text.svm b/vcl/qa/cppunit/svm/data/text.svm new file mode 100644 index 000000000..37da7f598 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/text.svm differ diff --git a/vcl/qa/cppunit/svm/data/textalign.svm b/vcl/qa/cppunit/svm/data/textalign.svm new file mode 100644 index 000000000..091c49876 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textalign.svm differ diff --git a/vcl/qa/cppunit/svm/data/textarray.svm b/vcl/qa/cppunit/svm/data/textarray.svm new file mode 100644 index 000000000..7863b03ce Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textarray.svm differ diff --git a/vcl/qa/cppunit/svm/data/textcolor.svm b/vcl/qa/cppunit/svm/data/textcolor.svm new file mode 100644 index 000000000..f55b3ccd7 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textcolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/textfillecolor.svm b/vcl/qa/cppunit/svm/data/textfillecolor.svm new file mode 100644 index 000000000..52a4f29f3 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textfillecolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/textline.svm b/vcl/qa/cppunit/svm/data/textline.svm new file mode 100644 index 000000000..1d8517823 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textline.svm differ diff --git a/vcl/qa/cppunit/svm/data/textlinecolor.svm b/vcl/qa/cppunit/svm/data/textlinecolor.svm new file mode 100644 index 000000000..786dfc465 Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textlinecolor.svm differ diff --git a/vcl/qa/cppunit/svm/data/textrectangle.svm b/vcl/qa/cppunit/svm/data/textrectangle.svm new file mode 100644 index 000000000..62c424d6a Binary files /dev/null and b/vcl/qa/cppunit/svm/data/textrectangle.svm differ diff --git a/vcl/qa/cppunit/svm/data/transparent.svm b/vcl/qa/cppunit/svm/data/transparent.svm new file mode 100644 index 000000000..40864b90a Binary files /dev/null and b/vcl/qa/cppunit/svm/data/transparent.svm differ diff --git a/vcl/qa/cppunit/svm/data/wallpaper.svm b/vcl/qa/cppunit/svm/data/wallpaper.svm new file mode 100644 index 000000000..8fca8c31f Binary files /dev/null and b/vcl/qa/cppunit/svm/data/wallpaper.svm differ diff --git a/vcl/qa/cppunit/svm/svmtest.cxx b/vcl/qa/cppunit/svm/svmtest.cxx new file mode 100644 index 000000000..413c3b7f6 --- /dev/null +++ b/vcl/qa/cppunit/svm/svmtest.cxx @@ -0,0 +1,1684 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if HAVE_FEATURE_OPENGL +#include +#endif +#include + +using namespace css; + +class SvmTest : public test::BootstrapFixture, public XmlTestTools +{ + OUString maDataUrl; + + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(maDataUrl) + sFileName; + } + + void checkRendering(ScopedVclPtrInstance const & pVirtualDev, const GDIMetaFile& rMetaFile); + + // write GDI Metafile to a file in data directory + // only use this for new tests to create the svm file + void writeToFile(GDIMetaFile& rMetaFile, OUString const & rName); + + GDIMetaFile writeAndReadStream(GDIMetaFile& rMetaFile, OUString const & rName = OUString()); + + GDIMetaFile readFile(const OUString& sName); + + xmlDocUniquePtr dumpMeta(const GDIMetaFile& rMetaFile); + + void checkVirtualDevice(const xmlDocUniquePtr& pDoc); + void checkErase(const xmlDocUniquePtr& pDoc); + + void checkPixel(const GDIMetaFile& rMetaFile); + void testPixel(); + + void checkPoint(const GDIMetaFile& rMetaFile); + void testPoint(); + + void checkLine(const GDIMetaFile& rMetaFile); + void testLine(); + + void checkRect(const GDIMetaFile& rMetaFile); + void testRect(); + + void checkRoundRect(const GDIMetaFile& rMetaFile); + void testRoundRect(); + + void checkEllipse(const GDIMetaFile& rMetaFile); + void testEllipse(); + + void checkArc(const GDIMetaFile& rMetaFile); + void testArc(); + + void checkPie(const GDIMetaFile& rMetaFile); + void testPie(); + + void checkChord(const GDIMetaFile& rMetaFile); + void testChord(); + + void checkPolyLine(const GDIMetaFile& rMetaFile); + void testPolyLine(); + + void checkPolygon(const GDIMetaFile& rMetaFile); + void testPolygon(); + + void checkPolyPolygon(const GDIMetaFile& rMetaFile); + void testPolyPolygon(); + + void checkText(const GDIMetaFile& rMetaFile); + void testText(); + + void checkTextArray(const GDIMetaFile& rMetaFile); + void testTextArray(); + + void checkStrechText(const GDIMetaFile& rMetaFile); + void testStrechText(); + + void checkTextRect(const GDIMetaFile& rMetaFile); + void testTextRect(); + + void checkTextLine(const GDIMetaFile& rMetaFile); + void testTextLine(); + + void checkBitmaps(const GDIMetaFile& rMetaFile); + void testBitmaps(); + + void checkBitmapExs(const GDIMetaFile& rMetaFile); + void testBitmapExs(); + + void checkMasks(const GDIMetaFile& rMetaFile); + void testMasks(); + + void checkGradient(const GDIMetaFile& rMetaFile); + void testGradient(); + + //void checkGradientEx(const GDIMetaFile& rMetaFile); + void testGradientEx(); + + void checkHatch(const GDIMetaFile& rMetaFile); + void testHatch(); + + void checkWallpaper(const GDIMetaFile& rMetaFile); + void testWallpaper(); + + void checkClipRegion(const GDIMetaFile& rMetaFile); + void testClipRegion(); + + //void checkIntersectRectClipRegion(const GDIMetaFile& rMetaFile); + void testIntersectRectClipRegion(); + + //void checkIntersectRegionClipRegion(const GDIMetaFile& rMetaFile); + void testIntersectRegionClipRegion(); + + //void checkMoveClipRegion(const GDIMetaFile& rMetaFile); + void testMoveClipRegion(); + + void checkLineColor(const GDIMetaFile& rMetaFile); + void testLineColor(); + + void checkFillColor(const GDIMetaFile& rMetaFile); + void testFillColor(); + + void checkTextColor(const GDIMetaFile& rMetaFile); + void testTextColor(); + + void checkTextFillColor(const GDIMetaFile& rMetaFile); + void testTextFillColor(); + + void checkTextLineColor(const GDIMetaFile& rMetaFile); + void testTextLineColor(); + + void checkOverLineColor(const GDIMetaFile& rMetaFile); + void testOverLineColor(); + + void checkTextAlign(const GDIMetaFile& rMetaFile); + void testTextAlign(); + + //void checkMapMode(const GDIMetaFile& rMetaFile); + void testMapMode(); + + //void checkFont(const GDIMetaFile& rMetaFile); + void testFont(); + + void checkPushPop(const GDIMetaFile& rMetaFile); + void testPushPop(); + + void checkRasterOp(const GDIMetaFile& rMetaFile); + void testRasterOp(); + + void checkTransparent(const GDIMetaFile& rMetaFile); + void testTransparent(); + + //void checkFloatTransparent(const GDIMetaFile& rMetaFile); + void testFloatTransparent(); + + //void checkEPS(const GDIMetaFile& rMetaFile); + void testEPS(); + + //void checkRefPoint(const GDIMetaFile& rMetaFile); + void testRefPoint(); + + //void checkComment(const GDIMetaFile& rMetaFile); + void testComment(); + + //void checkLayoutMode(const GDIMetaFile& rMetaFile); + void testLayoutMode(); + + //void checkTextLanguage(const GDIMetaFile& rMetaFile); + void testTextLanguage(); + +public: + SvmTest() + : BootstrapFixture(true, false) + , maDataUrl("/vcl/qa/cppunit/svm/data/") + {} + + CPPUNIT_TEST_SUITE(SvmTest); + CPPUNIT_TEST(testPixel); + CPPUNIT_TEST(testPoint); + CPPUNIT_TEST(testLine); + CPPUNIT_TEST(testRect); + CPPUNIT_TEST(testRoundRect); + CPPUNIT_TEST(testEllipse); + CPPUNIT_TEST(testArc); + CPPUNIT_TEST(testPie); + CPPUNIT_TEST(testChord); + CPPUNIT_TEST(testPolyLine); + CPPUNIT_TEST(testPolygon); + CPPUNIT_TEST(testPolyPolygon); + CPPUNIT_TEST(testText); + CPPUNIT_TEST(testTextArray); + CPPUNIT_TEST(testStrechText); + CPPUNIT_TEST(testTextRect); + CPPUNIT_TEST(testTextLine); + CPPUNIT_TEST(testBitmaps); // BMP, BMPSCALE, BMPSCALEPART + CPPUNIT_TEST(testBitmapExs); // BMPEX, BMPEXSCALE, BMPEXSCALEPART + CPPUNIT_TEST(testMasks); // MASK, MASKSCALE, MASKSCALEPART + CPPUNIT_TEST(testGradient); + CPPUNIT_TEST(testGradientEx); + CPPUNIT_TEST(testHatch); + CPPUNIT_TEST(testWallpaper); + CPPUNIT_TEST(testClipRegion); + CPPUNIT_TEST(testIntersectRectClipRegion); + CPPUNIT_TEST(testIntersectRegionClipRegion); + CPPUNIT_TEST(testMoveClipRegion); + CPPUNIT_TEST(testLineColor); + CPPUNIT_TEST(testFillColor); + CPPUNIT_TEST(testTextColor); + CPPUNIT_TEST(testTextFillColor); + CPPUNIT_TEST(testTextLineColor); + CPPUNIT_TEST(testOverLineColor); + CPPUNIT_TEST(testTextAlign); + CPPUNIT_TEST(testMapMode); + CPPUNIT_TEST(testFont); + CPPUNIT_TEST(testPushPop); + CPPUNIT_TEST(testRasterOp); + CPPUNIT_TEST(testTransparent); + CPPUNIT_TEST(testFloatTransparent); + CPPUNIT_TEST(testEPS); + CPPUNIT_TEST(testRefPoint); + CPPUNIT_TEST(testComment); + CPPUNIT_TEST(testLayoutMode); + CPPUNIT_TEST(testTextLanguage); + + CPPUNIT_TEST_SUITE_END(); +}; + +static void setupBaseVirtualDevice(VirtualDevice& rDevice, GDIMetaFile& rMeta) +{ + rDevice.SetConnectMetaFile(&rMeta); + Size aVDSize(10, 10); + rDevice.SetOutputSizePixel(aVDSize); + rDevice.SetBackground(Wallpaper(COL_LIGHTRED)); + rDevice.Erase(); +} + +void SvmTest::checkRendering(ScopedVclPtrInstance const & pVirtualDev, const GDIMetaFile& rMetaFile) +{ + BitmapEx aSourceBitmapEx = pVirtualDev->GetBitmapEx(Point(), Size(10, 10)); + ScopedVclPtrInstance pVirtualDevResult; + const_cast(rMetaFile).Play(pVirtualDevResult.get()); + BitmapEx aResultBitmapEx = pVirtualDev->GetBitmapEx(Point(), Size(10, 10)); + + const bool bWriteCompareBitmap = false; + + if (bWriteCompareBitmap) + { + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + + { + SvFileStream aStream(aTempFile.GetURL() + ".source.png", StreamMode::WRITE | StreamMode::TRUNC); + vcl::PNGWriter aPNGWriter(aSourceBitmapEx); + aPNGWriter.Write(aStream); + } + { + SvFileStream aStream(aTempFile.GetURL() + ".result.png", StreamMode::WRITE | StreamMode::TRUNC); + vcl::PNGWriter aPNGWriter(aResultBitmapEx); + aPNGWriter.Write(aStream); + } + } + CPPUNIT_ASSERT_EQUAL(aSourceBitmapEx.GetChecksum(), aResultBitmapEx.GetChecksum()); +} + +static GDIMetaFile readMetafile(const OUString& rUrl) +{ + GDIMetaFile aResultMetafile; + SvFileStream aFileStream(rUrl, StreamMode::READ); + aFileStream.Seek(STREAM_SEEK_TO_BEGIN); + aResultMetafile.Read(aFileStream); + return aResultMetafile; +} + +static void writeMetaFile(GDIMetaFile& rInputMetafile, const OUString& rUrl) +{ + SvFileStream aFileStream(rUrl, StreamMode::WRITE); + aFileStream.Seek(STREAM_SEEK_TO_BEGIN); + rInputMetafile.Write(aFileStream); + aFileStream.Close(); +} + +void SvmTest::writeToFile(GDIMetaFile& rMetaFile, OUString const & rName) +{ + if (rName.isEmpty()) + return; + OUString sFilePath = getFullUrl(rName); + writeMetaFile(rMetaFile, sFilePath); +} + +GDIMetaFile SvmTest::writeAndReadStream(GDIMetaFile& rMetaFile, OUString const & rName) +{ + if (!rName.isEmpty()) + writeToFile(rMetaFile, rName); + + SvMemoryStream aStream; + rMetaFile.Write(aStream); + aStream.Seek(STREAM_SEEK_TO_BEGIN); + + GDIMetaFile aResultMetafile; + aResultMetafile.Read(aStream); + return aResultMetafile; +} + +GDIMetaFile SvmTest::readFile(const OUString& sName) +{ + OUString sFilePath = getFullUrl(sName); + return readMetafile(sFilePath); +} + +xmlDocUniquePtr SvmTest::dumpMeta(const GDIMetaFile& rMetaFile) +{ + MetafileXmlDump dumper; + xmlDocUniquePtr pDoc = dumpAndParse(dumper, rMetaFile); + CPPUNIT_ASSERT (pDoc); + + checkVirtualDevice(pDoc); + checkErase(pDoc); + + return pDoc; +} + +void SvmTest::checkVirtualDevice(const xmlDocUniquePtr& pDoc) +{ + assertXPath(pDoc, "/metafile/linecolor[1]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[1]", "color", "#ffffff"); + + assertXPathAttrs(pDoc, "/metafile/rect[1]", { + {"left", "0"}, {"top", "0"}, + {"right", "9"}, {"bottom", "9"} + }); + + assertXPath(pDoc, "/metafile/linecolor[2]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[2]", "color", "#ffffff"); +} + +void SvmTest::checkErase(const xmlDocUniquePtr& pDoc) +{ + assertXPath(pDoc, "/metafile/linecolor[3]", "color", "#000000"); + assertXPath(pDoc, "/metafile/fillcolor[3]", "color", "#ff0000"); + + assertXPathAttrs(pDoc, "/metafile/rect[2]", { + {"left", "0"}, {"top", "0"}, + {"right", "9"}, {"bottom", "9"} + }); +} + +void SvmTest::checkPixel(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/pixel[1]", { + {"x", "8"}, {"y", "1"}, {"color", "#008000"}, + }); + + assertXPathAttrs(pDoc, "/metafile/pixel[2]", { + {"x", "1"}, {"y", "8"}, {"color", "#000080"}, + }); +} + +void SvmTest::testPixel() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawPixel(Point(8, 1), COL_GREEN); + pVirtualDev->DrawPixel(Point(1, 8), COL_BLUE); + + checkPixel(writeAndReadStream(aGDIMetaFile)); + checkPixel(readFile("pixel.svm")); +} + +void SvmTest::checkPoint(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/point[1]", { + {"x", "4"}, {"y", "4"} + }); +} + +void SvmTest::testPoint() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawPixel(Point(4, 4)); + + checkPoint(writeAndReadStream(aGDIMetaFile)); + checkPoint(readFile("point.svm")); +} + +void SvmTest::checkLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/line[1]", { + {"startx", "1"}, {"starty", "1"}, + {"endx", "8"}, {"endy", "8"}, + }); + + assertXPathAttrs(pDoc, "/metafile/line[1]", { + {"style", "solid"}, {"width", "0"}, + {"dashlen", "0"}, {"dashcount", "0"}, + {"dotlen", "0"}, {"dotcount", "0"}, + {"distance", "0"}, + {"join", "round"}, {"cap", "butt"} + }); + + assertXPathAttrs(pDoc, "/metafile/line[2]", { + {"startx", "1"}, {"starty", "8"}, + {"endx", "8"}, {"endy", "1"}, + }); + + assertXPathAttrs(pDoc, "/metafile/line[2]", { + {"style", "dash"}, {"width", "7"}, + {"dashlen", "5"}, {"dashcount", "4"}, + {"dotlen", "3"}, {"dotcount", "2"}, + {"distance", "1"}, + {"join", "miter"}, {"cap", "round"} + }); +} + +void SvmTest::testLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawLine(Point(1, 1), Point(8, 8)); + LineInfo aLineInfo(LineStyle::Dash, 7); + aLineInfo.SetDashLen(5); + aLineInfo.SetDashCount(4); + aLineInfo.SetDotLen(3); + aLineInfo.SetDotCount(2); + aLineInfo.SetDistance(1); + aLineInfo.SetLineJoin(basegfx::B2DLineJoin::Miter); + aLineInfo.SetLineCap(css::drawing::LineCap_ROUND); + pVirtualDev->DrawLine(Point(1, 8), Point(8, 1), aLineInfo); + + checkLine(writeAndReadStream(aGDIMetaFile)); + checkLine(readFile("line.svm")); +} + +void SvmTest::checkRect(const GDIMetaFile& rMetaFile) +{ + + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/rect[3]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + }); +} + +void SvmTest::testRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawRect(tools::Rectangle(Point(1, 2), Size(4, 4))); + + checkRect(writeAndReadStream(aGDIMetaFile)); + checkRect(readFile("rect.svm")); +} + +void SvmTest::checkRoundRect(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/roundrect[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + {"horizontalround", "1"}, {"verticalround", "2"} + }); +} + +void SvmTest::testRoundRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawRect(tools::Rectangle(Point(1, 2), Size(4, 4)), 1, 2); + + checkRoundRect(writeAndReadStream(aGDIMetaFile)); + checkRoundRect(readFile("roundrect.svm")); +} + +void SvmTest::checkEllipse(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/ellipse[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + }); +} + +void SvmTest::testEllipse() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawEllipse(tools::Rectangle(Point(1, 2), Size(4, 4))); + + checkEllipse(writeAndReadStream(aGDIMetaFile)); + checkEllipse(readFile("ellipse.svm")); +} + +void SvmTest::checkArc(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/arc[1]", { + {"left", "1"}, {"top", "2"}, + {"right", "4"}, {"bottom", "5"}, + + {"startx", "10"}, {"starty", "11"}, + {"endx", "12"}, {"endy", "13"}, + }); +} + +void SvmTest::testArc() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawArc(tools::Rectangle(Point(1, 2), Size(4, 4)), Point(10, 11), Point(12, 13)); + + checkArc(writeAndReadStream(aGDIMetaFile)); + checkArc(readFile("arc.svm")); +} + +void SvmTest::checkPie(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/pie[1]", { + {"left", "11"}, {"top", "12"}, + {"right", "14"}, {"bottom", "15"}, + + {"startx", "20"}, {"starty", "21"}, + {"endx", "22"}, {"endy", "23"}, + }); +} + +void SvmTest::testPie() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawPie(tools::Rectangle(Point(11, 12), Size(4, 4)), Point(20, 21), Point(22, 23)); + + checkPie(writeAndReadStream(aGDIMetaFile)); + checkPie(readFile("pie.svm")); +} + +void SvmTest::checkChord(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPath(pDoc, "/metafile/linecolor[5]", "color", "#123456"); + assertXPath(pDoc, "/metafile/fillcolor[5]", "color", "#654321"); + + assertXPathAttrs(pDoc, "/metafile/chord[1]", { + {"left", "21"}, {"top", "22"}, + {"right", "24"}, {"bottom", "25"}, + + {"startx", "30"}, {"starty", "31"}, + {"endx", "32"}, {"endy", "33"}, + }); +} + +void SvmTest::testChord() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(Color(0x123456)); + pVirtualDev->SetFillColor(Color(0x654321)); + + pVirtualDev->DrawChord(tools::Rectangle(Point(21, 22), Size(4, 4)), Point(30, 31), Point(32, 33)); + + checkChord(writeAndReadStream(aGDIMetaFile)); + checkChord(readFile("chord.svm")); +} + +void SvmTest::checkPolyLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polyline[1]", { + {"style", "solid"}, {"width", "0"}, + {"dashlen", "0"}, {"dashcount", "0"}, + {"dotlen", "0"}, {"dotcount", "0"}, + {"distance", "0"}, + {"join", "round"}, {"cap", "butt"} + }); + + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polyline[2]", { + {"style", "dash"}, {"width", "7"}, + {"dashlen", "5"}, {"dashcount", "4"}, + {"dotlen", "3"}, {"dotcount", "2"}, + {"distance", "1"}, + {"join", "miter"}, {"cap", "round"} + }); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polyline[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolyLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + pVirtualDev->DrawPolyLine(aPolygon); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + LineInfo aLineInfo(LineStyle::Dash, 7); + aLineInfo.SetDashLen(5); + aLineInfo.SetDashCount(4); + aLineInfo.SetDotLen(3); + aLineInfo.SetDotCount(2); + aLineInfo.SetDistance(1); + aLineInfo.SetLineJoin(basegfx::B2DLineJoin::Miter); + aLineInfo.SetLineCap(css::drawing::LineCap_ROUND); + + pVirtualDev->DrawPolyLine(aPolygonWithControl, aLineInfo); + + checkPolyLine(writeAndReadStream(aGDIMetaFile)); + checkPolyLine(readFile("polyline.svm")); +} + +void SvmTest::checkPolygon(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polygon[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolygon() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + pVirtualDev->DrawPolygon(aPolygon); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + pVirtualDev->DrawPolygon(aPolygonWithControl); + + checkPolygon(writeAndReadStream(aGDIMetaFile)); + checkPolygon(readFile("polygon.svm")); +} + +void SvmTest::checkPolyPolygon(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[1]", {{"x", "1"}, {"y", "8"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[2]", {{"x", "2"}, {"y", "7"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[1]/point[3]", {{"x", "3"}, {"y", "6"}}); + + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[1]", {{"x", "8"}, {"y", "1"}, {"flags", "normal"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[2]", {{"x", "7"}, {"y", "2"}, {"flags", "control"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[3]", {{"x", "6"}, {"y", "3"}, {"flags", "smooth"}}); + assertXPathAttrs(pDoc, "/metafile/polypolygon[1]/polygon[2]/point[4]", {{"x", "5"}, {"y", "4"}, {"flags", "symmetric"}}); +} + +void SvmTest::testPolyPolygon() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::Polygon aPolygonWithControl(4); + aPolygonWithControl.SetPoint(Point(8, 1), 0); + aPolygonWithControl.SetPoint(Point(7, 2), 1); + aPolygonWithControl.SetPoint(Point(6, 3), 2); + aPolygonWithControl.SetPoint(Point(5, 4), 3); + + aPolygonWithControl.SetFlags(0, PolyFlags::Normal); + aPolygonWithControl.SetFlags(1, PolyFlags::Control); + aPolygonWithControl.SetFlags(2, PolyFlags::Smooth); + aPolygonWithControl.SetFlags(3, PolyFlags::Symmetric); + + tools::PolyPolygon aPolyPolygon(2); + aPolyPolygon.Insert(aPolygon); + aPolyPolygon.Insert(aPolygonWithControl); + + pVirtualDev->DrawPolyPolygon(aPolyPolygon); + + checkPolyPolygon(writeAndReadStream(aGDIMetaFile)); + checkPolyPolygon(readFile("polypolygon.svm")); +} + +void SvmTest::checkText(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/text[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "2"}, + }); + + assertXPathContent(pDoc, "/metafile/text[1]/textcontent", "xABC"); +} + +void SvmTest::testText() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->DrawText(Point(4,6), "xABC", 1, 2); + + checkText(writeAndReadStream(aGDIMetaFile)); + checkText(readFile("text.svm")); +} + +void SvmTest::checkTextArray(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textarray[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "4"}, + }); + assertXPathContent(pDoc, "/metafile/textarray[1]/dxarray", "15 20 25 "); + assertXPathContent(pDoc, "/metafile/textarray[1]/text", "123456"); +} + +void SvmTest::testTextArray() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + long const aDX[] = { 10, 15, 20, 25, 30, 35 }; + pVirtualDev->DrawTextArray(Point(4,6), "123456", aDX, 1, 4); + + checkTextArray(writeAndReadStream(aGDIMetaFile)); + checkTextArray(readFile("textarray.svm")); +} + +void SvmTest::checkStrechText(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/stretchtext[1]", { + {"x", "4"}, {"y", "6"}, {"index", "1"}, {"length", "4"}, {"width", "10"} + }); + + assertXPathContent(pDoc, "/metafile/stretchtext[1]/textcontent", "123456"); +} + +void SvmTest::testStrechText() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawStretchText(Point(4,6), 10, "123456", 1, 4); + + checkStrechText(writeAndReadStream(aGDIMetaFile)); + checkStrechText(readFile("strecthtext.svm")); +} + +void SvmTest::checkTextRect(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textrect[1]", { + {"left", "0"}, {"top", "0"}, {"right", "4"}, {"bottom", "4"} + }); + assertXPathContent(pDoc, "/metafile/textrect[1]/textcontent", "123456"); + assertXPathContent(pDoc, "/metafile/textrect[1]/style", "Center"); +} + +void SvmTest::testTextRect() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawText(tools::Rectangle(Point(0,0), Size(5,5)), "123456", DrawTextFlags::Center); + + checkTextRect(writeAndReadStream(aGDIMetaFile)); + checkTextRect(readFile("textrectangle.svm")); +} + +void SvmTest::checkTextLine(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textline[1]", { + {"x", "4"}, {"y", "6"}, {"width", "10"}, + {"strikeout", "single"}, {"underline", "single"}, {"overline", "single"} + }); +} + +void SvmTest::testTextLine() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + pVirtualDev->DrawTextLine(Point(4,6), 10, STRIKEOUT_SINGLE, LINESTYLE_SINGLE, LINESTYLE_SINGLE); + + checkTextLine(writeAndReadStream(aGDIMetaFile)); + checkTextLine(readFile("textline.svm")); +} + +void SvmTest::checkBitmaps(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + if (SkiaHelper::isVCLSkiaEnabled()) + return; // TODO SKIA using CRCs is broken (the idea of it) + + OUString crc1 = "b8dee5da"; + OUString crc2 = "281fc589"; + OUString crc3 = "5e01ddcc"; +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + { + // OpenGL uses a different scaling algorithm and also a different RGB order. + crc1 = "5e01ddcc"; + crc2 = "281fc589"; + crc3 = "b8dee5da"; + } +#endif + + assertXPathAttrs(pDoc, "/metafile/bmp[1]", {{"x", "1"}, {"y", "2"}, {"crc", crc1}}); + assertXPathAttrs(pDoc, "/metafile/bmpscale[1]", { + {"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, {"crc", crc2} + }); + assertXPathAttrs(pDoc, "/metafile/bmpscalepart[1]", { + {"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"}, + {"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"}, + {"crc", crc3} + }); +} + +void SvmTest::testBitmaps() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Bitmap aBitmap1(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap1); + pAccess->Erase(COL_RED); + } + Bitmap aBitmap2(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap2); + pAccess->Erase(COL_GREEN); + } + Bitmap aBitmap3(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap3); + pAccess->Erase(COL_BLUE); + } + pVirtualDev->DrawBitmap(Point(1, 2), aBitmap1); + pVirtualDev->DrawBitmap(Point(1, 2), Size(3, 4), aBitmap2); + pVirtualDev->DrawBitmap(Point(1, 2), Size(3, 4), Point(2, 1), Size(4, 3), aBitmap3); + + { + GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile); + checkBitmaps(aReloadedGDIMetaFile); + checkRendering(pVirtualDev, aReloadedGDIMetaFile); + } + { + GDIMetaFile aFileGDIMetaFile = readFile("bitmaps.svm"); + checkBitmaps(aFileGDIMetaFile); + checkRendering(pVirtualDev, aFileGDIMetaFile); + } +} + +void SvmTest::checkBitmapExs(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + if (SkiaHelper::isVCLSkiaEnabled()) + return; // TODO SKIA using CRCs is broken (the idea of it) + + std::vector aExpectedCRC; + +#if HAVE_FEATURE_OPENGL + if (OpenGLHelper::isVCLOpenGLEnabled()) + { + aExpectedCRC.insert(aExpectedCRC.end(), + { + "08feb5d3", + "281fc589", + "b8dee5da", + "4df0e464", + "7d3a8da3", + "1426653b", + "4fd547df", + "71efc447", + }); + } + else +#endif + { + aExpectedCRC.insert(aExpectedCRC.end(), + { + "d8377d4f", + "281fc589", + "5e01ddcc", + "4df0e464", + "34434a50", + "d1736327", + "b37875c2", + "a85d44b8", + }); + } + + assertXPathAttrs(pDoc, "/metafile/bmpex[1]", { + {"x", "1"}, {"y", "1"}, {"crc", aExpectedCRC[0]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpexscale[1]", { + {"x", "5"}, {"y", "0"}, {"width", "2"}, {"height", "3"}, + {"crc", aExpectedCRC[1]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpexscalepart[1]", { + {"destx", "7"}, {"desty", "1"}, {"destwidth", "2"}, {"destheight", "2"}, + {"srcx", "0"}, {"srcy", "0"}, {"srcwidth", "3"}, {"srcheight", "4"}, + {"crc", aExpectedCRC[2]}, {"transparenttype", "bitmap"} + }); + +#ifndef MACOSX + assertXPathAttrs(pDoc, "/metafile/bmpex[2]", { + {"x", "6"}, {"y", "6"}, {"crc", aExpectedCRC[3]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[3]", { + {"x", "0"}, {"y", "6"}, {"crc", aExpectedCRC[4]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[4]", { + {"x", "2"}, {"y", "6"}, {"crc", aExpectedCRC[5]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[5]", { + {"x", "0"}, {"y", "8"}, {"crc", aExpectedCRC[6]}, {"transparenttype", "bitmap"} + }); + assertXPathAttrs(pDoc, "/metafile/bmpex[6]", { + {"x", "2"}, {"y", "8"}, {"crc", aExpectedCRC[7]}, {"transparenttype", "bitmap"} + }); +#endif +} + +void SvmTest::testBitmapExs() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + // DrawBitmapEx + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_YELLOW); + } + + pVirtualDev->DrawBitmapEx(Point(1, 1), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - Scale + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_GREEN); + } + pVirtualDev->DrawBitmapEx(Point(5, 0), Size(2, 3), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - Scale - Part + { + Bitmap aBitmap(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_BLUE); + } + pVirtualDev->DrawBitmapEx(Point(7, 1), Size(2, 2), Point(0, 0), Size(3, 4), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 50% transparent + { + Bitmap aBitmap(Size(4, 4), 24); + AlphaMask aAlpha(Size(4, 4)); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + + AlphaScopedWriteAccess pAlphaAccess(aAlpha); + pAlphaAccess->Erase(Color(128, 128, 128)); + } + pVirtualDev->DrawBitmapEx(Point(6, 6), BitmapEx(aBitmap, aAlpha)); + } + + // DrawBitmapEx - 1-bit + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N1BitThreshold); + pVirtualDev->DrawBitmapEx(Point(0, 6), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 4-bit + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N4BitColors); + pVirtualDev->DrawBitmapEx(Point(2, 6), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 8-bit Color + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N8BitColors); + pVirtualDev->DrawBitmapEx(Point(0, 8), BitmapEx(aBitmap, COL_WHITE)); + } + + // DrawBitmapEx - 8-bit Grey + { + Bitmap aBitmap(Size(2, 2), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap); + pAccess->Erase(COL_MAGENTA); + } + aBitmap.Convert(BmpConversion::N8BitGreys); + pVirtualDev->DrawBitmapEx(Point(2, 8), BitmapEx(aBitmap, COL_WHITE)); + } + + { + GDIMetaFile aReloadedGDIMetaFile = writeAndReadStream(aGDIMetaFile); + checkBitmapExs(aReloadedGDIMetaFile); + checkRendering(pVirtualDev, aReloadedGDIMetaFile); + } + { + GDIMetaFile aFileGDIMetaFile = readFile("bitmapexs.svm"); + checkBitmapExs(aFileGDIMetaFile); + checkRendering(pVirtualDev, aFileGDIMetaFile); + } +} + +void SvmTest::checkMasks(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/mask[1]", { + {"x", "1"}, {"y", "2"}, + {"color", "#000000"} + }); + assertXPathAttrs(pDoc, "/metafile/maskscale[1]", { + {"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, + {"color", "#000000"} + }); + assertXPathAttrs(pDoc, "/metafile/maskscalepart[1]", { + {"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"}, + {"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"}, + {"color", "#ff0000"} + }); +} + +// TODO: Masks are kind-of special - we don't persist the color attribute (it is +// always #000000) of the meta-action (which is wrong), but rely on alpha to do +// the right thing. +void SvmTest::testMasks() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Bitmap aBitmap1(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap1); + pAccess->Erase(COL_RED); + } + Bitmap aBitmap2(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap2); + pAccess->Erase(COL_GREEN); + } + Bitmap aBitmap3(Size(4,4), 24); + { + BitmapScopedWriteAccess pAccess(aBitmap3); + pAccess->Erase(COL_BLUE); + } + + pVirtualDev->DrawMask(Point(1, 2), aBitmap1, COL_LIGHTRED); + pVirtualDev->DrawMask(Point(1, 2), Size(3, 4), aBitmap2, COL_LIGHTRED); + pVirtualDev->DrawMask(Point(1, 2), Size(3, 4), Point(2, 1), Size(4, 3), aBitmap3, COL_LIGHTRED, MetaActionType::MASKSCALEPART); + + checkMasks(writeAndReadStream(aGDIMetaFile)); + checkMasks(readFile("masks.svm")); +} + +void SvmTest::checkGradient(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/gradient[1]", { + {"style", "Linear"}, + {"startcolor", "#ffffff"}, + {"endcolor", "#000000"}, + {"angle", "0"}, + {"border", "0"}, + {"offsetx", "50"}, + {"offsety", "50"}, + {"startintensity", "100"}, + {"endintensity", "100"}, + {"steps", "0"}, + }); + assertXPathAttrs(pDoc, "/metafile/gradient[1]/rectangle", { + {"left", "1"}, + {"top", "2"}, + {"right", "4"}, + {"bottom", "6"}, + }); + + assertXPathAttrs(pDoc, "/metafile/gradient[2]", { + {"style", "Radial"}, + {"startcolor", "#ff0000"}, + {"endcolor", "#00ff00"}, + {"angle", "55"}, + {"border", "10"}, + {"offsetx", "22"}, + {"offsety", "24"}, + {"startintensity", "4"}, + {"endintensity", "14"}, + {"steps", "64"}, + }); + assertXPathAttrs(pDoc, "/metafile/gradient[2]/rectangle", { + {"left", "3"}, + {"top", "4"}, + {"right", "3"}, + {"bottom", "5"}, + }); +} + +void SvmTest::testGradient() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Rectangle aRectangle(Point(1, 2), Size(4,5)); + + Gradient aGradient(GradientStyle::Linear, COL_WHITE, COL_BLACK); + pVirtualDev->DrawGradient(aRectangle, aGradient); + + tools::Rectangle aRectangle2(Point(3, 4), Size(1,2)); + + Gradient aGradient2; + aGradient2.SetStyle(GradientStyle::Radial); + aGradient2.SetStartColor(COL_LIGHTRED); + aGradient2.SetEndColor(COL_LIGHTGREEN); + aGradient2.SetAngle(55); + aGradient2.SetBorder(10); + aGradient2.SetOfsX(22); + aGradient2.SetOfsY(24); + aGradient2.SetStartIntensity(4); + aGradient2.SetEndIntensity(14); + aGradient2.SetSteps(64); + pVirtualDev->DrawGradient(aRectangle2, aGradient2); + + checkGradient(writeAndReadStream(aGDIMetaFile)); + checkGradient(readFile("gradient.svm")); +} + +void SvmTest::testGradientEx() +{} + +void SvmTest::checkHatch(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[1]", { + {"x", "1"}, {"y", "8"}, + }); + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[2]", { + {"x", "2"}, {"y", "7"}, + }); + assertXPathAttrs(pDoc, "/metafile/hatch[1]/polygon/point[3]", { + {"x", "3"}, {"y", "6"}, + }); + + assertXPathAttrs(pDoc, "/metafile/hatch[1]/hatch", { + {"style", "Single"}, + {"color", "#ffff00"}, + {"distance", "15"}, + {"angle", "900"}, + }); +} + +void SvmTest::testHatch() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::PolyPolygon aPolyPolygon(1); + aPolyPolygon.Insert(aPolygon); + + Hatch aHatch(HatchStyle::Single, COL_YELLOW, 15, 900); + + pVirtualDev->DrawHatch(aPolyPolygon, aHatch); + + checkHatch(writeAndReadStream(aGDIMetaFile)); + checkHatch(readFile("hatch.svm")); +} + +void SvmTest::checkWallpaper(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + // Funny enough - we don't serialize the rectangle of the wallpaper so it's always EMPTY + assertXPathAttrs(pDoc, "/metafile/wallpaper[1]", + { + {"left", "0"}, + {"top", "0"}, + {"right", "empty"}, + {"bottom", "empty"}, + }); + + assertXPathAttrs(pDoc, "/metafile/wallpaper[1]/wallpaper", + { + {"color", "#00ff00"}, + {"style", "Tile"}, + {"fixed", "true"}, + {"scrollable", "true"}, + }); +} + +void SvmTest::testWallpaper() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + Wallpaper aWallpaper(COL_LIGHTGREEN); + pVirtualDev->DrawWallpaper(tools::Rectangle(Point(1, 1), Size(3, 3)), aWallpaper); + + checkWallpaper(writeAndReadStream(aGDIMetaFile)); + checkWallpaper(readFile("wallpaper.svm")); +} + +void SvmTest::checkClipRegion(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/clipregion[1]", { + {"left", "2"}, + {"top", "2"}, + {"right", "5"}, + {"bottom", "5"}, + }); +} + +void SvmTest::testClipRegion() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + vcl::Region aRegion(tools::Rectangle(Point(2, 2), Size(4, 4))); + + // TODO + // explicit Region(const tools::Polygon& rPolygon); + // explicit Region(const tools::PolyPolygon& rPolyPoly); + // explicit Region(const basegfx::B2DPolyPolygon&); + pVirtualDev->SetClipRegion(aRegion); + + checkClipRegion(writeAndReadStream(aGDIMetaFile)); + checkClipRegion(readFile("clipregion.svm")); +} + +void SvmTest::testIntersectRectClipRegion() +{} +void SvmTest::testIntersectRegionClipRegion() +{} +void SvmTest::testMoveClipRegion() +{} + +void SvmTest::checkLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/linecolor[1]", { + {"color", "#654321"}, + }); +} + +void SvmTest::testLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetLineColor(Color(0x654321)); + pVirtualDev->Pop(); + + checkLineColor(writeAndReadStream(aGDIMetaFile)); + checkLineColor(readFile("linecolor.svm")); +} + +void SvmTest::checkFillColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/fillcolor[1]", { + {"color", "#456789"}, + }); +} + +void SvmTest::testFillColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetFillColor(Color(0x456789)); + pVirtualDev->Pop(); + + checkFillColor(writeAndReadStream(aGDIMetaFile)); + checkFillColor(readFile("fillcolor.svm")); +} + +void SvmTest::checkTextColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textcolor[1]", { + {"color", "#123456"}, + }); +} + +void SvmTest::testTextColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextColor(Color(0x123456)); + + checkTextColor(writeAndReadStream(aGDIMetaFile)); + checkTextColor(readFile("textcolor.svm")); +} + +void SvmTest::checkTextFillColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textfillcolor[1]", { + {"color", "#234567"}, + }); +} + +void SvmTest::testTextFillColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextFillColor(Color(0x234567)); + + checkTextFillColor(writeAndReadStream(aGDIMetaFile)); + checkTextFillColor(readFile("textfillecolor.svm")); +} + +void SvmTest::checkTextLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textlinecolor[1]", { + {"color", "#345678"}, + }); +} + +void SvmTest::testTextLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextLineColor(Color(0x345678)); + + checkTextLineColor(writeAndReadStream(aGDIMetaFile)); + checkTextLineColor(readFile("textlinecolor.svm")); +} + +void SvmTest::checkOverLineColor(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push/overlinecolor[1]", { + {"color", "#345678"}, + }); +} + +void SvmTest::testOverLineColor() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->Push(); + pVirtualDev->SetOverlineColor(Color(0x345678)); + pVirtualDev->Pop(); + + checkOverLineColor(writeAndReadStream(aGDIMetaFile)); + checkOverLineColor(readFile("overlinecolor.svm")); +} + +void SvmTest::checkTextAlign(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/textalign[1]", { + {"align", "bottom"}, + }); +} + +void SvmTest::testTextAlign() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetTextAlign(TextAlign::ALIGN_BOTTOM); + + checkTextAlign(writeAndReadStream(aGDIMetaFile)); + checkTextAlign(readFile("textalign.svm")); +} + +void SvmTest::testMapMode() +{} +void SvmTest::testFont() +{} + +void SvmTest::checkPushPop(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/push[1]", {{"flags", "PushAll"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/linecolor[1]", {{"color", "#800000"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/line[1]", { + {"startx", "4"}, {"starty", "4"}, + {"endx", "6"}, {"endy", "6"}, + }); + assertXPathAttrs(pDoc, "/metafile/push[1]/push[1]", {{"flags", "PushLineColor, PushFillColor"}}); + assertXPathAttrs(pDoc, "/metafile/push[1]/push[1]/line[1]", { + {"startx", "5"}, {"starty", "5"}, + {"endx", "7"}, {"endy", "7"}, + }); +} + +void SvmTest::testPushPop() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetLineColor(COL_YELLOW); + pVirtualDev->Push(); + pVirtualDev->SetLineColor(COL_RED); + pVirtualDev->DrawLine(Point(4,4), Point(6,6)); + pVirtualDev->Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR); + pVirtualDev->SetLineColor(COL_LIGHTRED); + pVirtualDev->DrawLine(Point(5,5), Point(7,7)); + pVirtualDev->Pop(); + pVirtualDev->Pop(); + pVirtualDev->DrawLine(Point(1,1), Point(8,8)); + + checkPushPop(writeAndReadStream(aGDIMetaFile)); + checkPushPop(readFile("pushpop.svm")); +} + +void SvmTest::checkRasterOp(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/rasterop[1]", { + {"operation", "xor"}, + }); +} + +void SvmTest::testRasterOp() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + pVirtualDev->SetRasterOp(RasterOp::Xor); + + checkRasterOp(writeAndReadStream(aGDIMetaFile)); + checkRasterOp(readFile("rasterop.svm")); +} + +void SvmTest::checkTransparent(const GDIMetaFile& rMetaFile) +{ + xmlDocUniquePtr pDoc = dumpMeta(rMetaFile); + + assertXPathAttrs(pDoc, "/metafile/transparent[1]", { + {"transparence", "50"}, + }); + + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[1]", { + {"x", "1"}, {"y", "8"}, + }); + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[2]", { + {"x", "2"}, {"y", "7"}, + }); + assertXPathAttrs(pDoc, "/metafile/transparent[1]/polygon/point[3]", { + {"x", "3"}, {"y", "6"}, + }); +} + +void SvmTest::testTransparent() +{ + GDIMetaFile aGDIMetaFile; + ScopedVclPtrInstance pVirtualDev; + setupBaseVirtualDevice(*pVirtualDev, aGDIMetaFile); + + tools::Polygon aPolygon(3); + aPolygon.SetPoint(Point(1, 8), 0); + aPolygon.SetPoint(Point(2, 7), 1); + aPolygon.SetPoint(Point(3, 6), 2); + + tools::PolyPolygon aPolyPolygon(1); + aPolyPolygon.Insert(aPolygon); + + pVirtualDev->DrawTransparent(aPolygon, 50); + + CPPUNIT_ASSERT(aGDIMetaFile.HasTransparentActions()); + checkTransparent(writeAndReadStream(aGDIMetaFile)); + checkTransparent(readFile("transparent.svm")); +} + +void SvmTest::testFloatTransparent() +{} + +void SvmTest::testEPS() +{} + +void SvmTest::testRefPoint() +{} + +void SvmTest::testComment() +{} + +void SvmTest::testLayoutMode() +{} + +void SvmTest::testTextLanguage() +{} + +CPPUNIT_TEST_SUITE_REGISTRATION(SvmTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/test_blocklist_evaluate.xml b/vcl/qa/cppunit/test_blocklist_evaluate.xml new file mode 100644 index 000000000..d7b72d6d8 --- /dev/null +++ b/vcl/qa/cppunit/test_blocklist_evaluate.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vcl/qa/cppunit/test_blocklist_parse.xml b/vcl/qa/cppunit/test_blocklist_parse.xml new file mode 100644 index 000000000..f9af4cb54 --- /dev/null +++ b/vcl/qa/cppunit/test_blocklist_parse.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vcl/qa/cppunit/timer.cxx b/vcl/qa/cppunit/timer.cxx new file mode 100644 index 000000000..4071cd0fd --- /dev/null +++ b/vcl/qa/cppunit/timer.cxx @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +/* + * Timers are evil beasts across platforms... + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +// #define TEST_WATCHDOG + +// Enables timer tests that appear to provoke windows under load unduly. +//#define TEST_TIMERPRECISION + +namespace { + +/// Avoid our timer tests just wedging the build if they fail. +class WatchDog : public osl::Thread +{ + sal_Int32 mnSeconds; +public: + explicit WatchDog(sal_Int32 nSeconds) : + Thread(), + mnSeconds( nSeconds ) + { + create(); + } + virtual void SAL_CALL run() override + { + osl::Thread::wait( std::chrono::seconds(mnSeconds) ); + fprintf(stderr, "ERROR: WatchDog timer thread expired, failing the test!\n"); + fflush(stderr); + CPPUNIT_ASSERT_MESSAGE("watchdog triggered", false); + } +}; + +} + +static WatchDog * aWatchDog = new WatchDog( 120 ); // random high number in secs + +class TimerTest : public test::BootstrapFixture +{ +public: + TimerTest() : BootstrapFixture(true, false) {} + + void testIdle(); + void testIdleMainloop(); +#ifdef TEST_WATCHDOG + void testWatchdog(); +#endif + void testDurations(); +#ifdef TEST_TIMERPRECISION + void testAutoTimer(); + void testMultiAutoTimers(); +#endif + void testAutoTimerStop(); + void testNestedTimer(); + void testSlowTimerCallback(); + void testTriggerIdleFromIdle(); + void testInvokedReStart(); + void testPriority(); + void testRoundRobin(); + + CPPUNIT_TEST_SUITE(TimerTest); + CPPUNIT_TEST(testIdle); + CPPUNIT_TEST(testIdleMainloop); +#ifdef TEST_WATCHDOG + CPPUNIT_TEST(testWatchdog); +#endif + CPPUNIT_TEST(testDurations); +#ifdef TEST_TIMERPRECISION + CPPUNIT_TEST(testAutoTimer); + CPPUNIT_TEST(testMultiAutoTimers); +#endif + CPPUNIT_TEST(testAutoTimerStop); + CPPUNIT_TEST(testNestedTimer); + CPPUNIT_TEST(testSlowTimerCallback); + CPPUNIT_TEST(testTriggerIdleFromIdle); + CPPUNIT_TEST(testInvokedReStart); + CPPUNIT_TEST(testPriority); + CPPUNIT_TEST(testRoundRobin); + + CPPUNIT_TEST_SUITE_END(); +}; + +#ifdef TEST_WATCHDOG +void TimerTest::testWatchdog() +{ + // out-wait the watchdog. + osl::Thread::wait( std::chrono::seconds(12) ); +} +#endif + +namespace { + +class IdleBool : public Idle +{ + bool &mrBool; +public: + explicit IdleBool( bool &rBool ) : + Idle( "IdleBool" ), mrBool( rBool ) + { + SetPriority( TaskPriority::LOWEST ); + Start(); + mrBool = false; + } + virtual void Invoke() override + { + mrBool = true; + Application::EndYield(); + } +}; + +} + +void TimerTest::testIdle() +{ + bool bTriggered = false; + IdleBool aTest( bTriggered ); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_MESSAGE("idle triggered", bTriggered); +} + +void TimerTest::testIdleMainloop() +{ + bool bTriggered = false; + IdleBool aTest( bTriggered ); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone + while (!bTriggered) + { + ImplSVData* pSVData = ImplGetSVData(); + + // can't test this via Application::Yield since this + // also processes all tasks directly via the scheduler. + pSVData->maAppData.mnDispatchLevel++; + pSVData->mpDefInst->DoYield(true, false); + pSVData->maAppData.mnDispatchLevel--; + } + CPPUNIT_ASSERT_MESSAGE("mainloop idle triggered", bTriggered); +} + +namespace { + +class TimerBool : public Timer +{ + bool &mrBool; +public: + TimerBool( sal_uLong nMS, bool &rBool ) : + Timer( "TimerBool" ), mrBool( rBool ) + { + SetTimeout( nMS ); + Start(); + mrBool = false; + } + virtual void Invoke() override + { + mrBool = true; + Application::EndYield(); + } +}; + +} + +void TimerTest::testDurations() +{ + static const sal_uLong aDurations[] = { 0, 1, 500, 1000 }; + for (size_t i = 0; i < SAL_N_ELEMENTS( aDurations ); i++) + { + bool bDone = false; + TimerBool aTimer( aDurations[i], bDone ); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bDone + while( !bDone ) + { + Application::Yield(); + } + } +} + +namespace { + +class AutoTimerCount : public AutoTimer +{ + sal_Int32 &mrCount; + const sal_Int32 mnMaxCount; + +public: + AutoTimerCount( sal_uLong nMS, sal_Int32 &rCount, + const sal_Int32 nMaxCount = -1 ) + : AutoTimer( "AutoTimerCount" ) + , mrCount( rCount ) + , mnMaxCount( nMaxCount ) + { + SetTimeout( nMS ); + Start(); + mrCount = 0; + } + + virtual void Invoke() override + { + ++mrCount; + CPPUNIT_ASSERT( mnMaxCount < 0 || mrCount <= mnMaxCount ); + if ( mrCount == mnMaxCount ) + Stop(); + } +}; + +} + +#ifdef TEST_TIMERPRECISION + +void TimerTest::testAutoTimer() +{ + const sal_Int32 nDurationMs = 30; + const sal_Int32 nEventsCount = 5; + const double exp = (nDurationMs * nEventsCount); + + sal_Int32 nCount = 0; + std::ostringstream msg; + + // Repeat when we have random latencies. + // This is expected on non-realtime OSes. + for (int i = 0; i < 10; ++i) + { + const auto start = std::chrono::high_resolution_clock::now(); + nCount = 0; + AutoTimerCount aCount(nDurationMs, nCount); + while (nCount < nEventsCount) { + Application::Yield(); + } + + const auto end = std::chrono::high_resolution_clock::now(); + double dur = std::chrono::duration(end - start).count(); + + msg << std::setprecision(2) << std::fixed + << "periodic multi-timer - dur: " + << dur << " (" << exp << ") ms." << std::endl; + + // +/- 20% should be reasonable enough a margin. + if (dur >= (exp * 0.8) && dur <= (exp * 1.2)) + { + // Success. + return; + } + } + + CPPUNIT_FAIL(msg.str().c_str()); +} + +void TimerTest::testMultiAutoTimers() +{ + // The behavior of the timers change drastically + // when multiple timers are present. + // The worst, in my tests, is when two + // timers with 1ms period exist with a + // third of much longer period. + + const sal_Int32 nDurationMsX = 5; + const sal_Int32 nDurationMsY = 10; + const sal_Int32 nDurationMs = 40; + const sal_Int32 nEventsCount = 5; + const double exp = (nDurationMs * nEventsCount); + const double expX = (exp / nDurationMsX); + const double expY = (exp / nDurationMsY); + + sal_Int32 nCountX = 0; + sal_Int32 nCountY = 0; + sal_Int32 nCount = 0; + std::ostringstream msg; + + // Repeat when we have random latencies. + // This is expected on non-realtime OSes. + for (int i = 0; i < 10; ++i) + { + nCountX = 0; + nCountY = 0; + nCount = 0; + + const auto start = std::chrono::high_resolution_clock::now(); + AutoTimerCount aCountX(nDurationMsX, nCountX); + AutoTimerCount aCountY(nDurationMsY, nCountY); + + AutoTimerCount aCount(nDurationMs, nCount); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle nCount + while (nCount < nEventsCount) { + Application::Yield(); + } + + const auto end = std::chrono::high_resolution_clock::now(); + double dur = std::chrono::duration(end - start).count(); + + msg << std::setprecision(2) << std::fixed << "periodic multi-timer - dur: " + << dur << " (" << exp << ") ms, nCount: " << nCount + << " (" << nEventsCount << "), nCountX: " << nCountX + << " (" << expX << "), nCountY: " << nCountY + << " (" << expY << ")." << std::endl; + + // +/- 20% should be reasonable enough a margin. + if (dur >= (exp * 0.8) && dur <= (exp * 1.2) && + nCountX >= (expX * 0.8) && nCountX <= (expX * 1.2) && + nCountY >= (expY * 0.8) && nCountY <= (expY * 1.2)) + { + // Success. + return; + } + } + + CPPUNIT_FAIL(msg.str().c_str()); +} +#endif // TEST_TIMERPRECISION + +void TimerTest::testAutoTimerStop() +{ + sal_Int32 nTimerCount = 0; + const sal_Int32 nMaxCount = 5; + AutoTimerCount aAutoTimer( 0, nTimerCount, nMaxCount ); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment TimerCount + while (nMaxCount != nTimerCount) + Application::Yield(); + CPPUNIT_ASSERT( !aAutoTimer.IsActive() ); + CPPUNIT_ASSERT( !Application::Reschedule() ); +} + +namespace { + +class YieldTimer : public Timer +{ +public: + explicit YieldTimer( sal_uLong nMS ) : Timer( "YieldTimer" ) + { + SetTimeout( nMS ); + Start(); + } + virtual void Invoke() override + { + for (int i = 0; i < 100; i++) + Application::Yield(); + } +}; + +} + +void TimerTest::testNestedTimer() +{ + sal_Int32 nCount = 0; + YieldTimer aCount(5); + AutoTimerCount aCountUp( 3, nCount ); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount + while (nCount < 20) + Application::Yield(); +} + +namespace { + +class SlowCallbackTimer : public Timer +{ + bool &mbSlow; +public: + SlowCallbackTimer( sal_uLong nMS, bool &bBeenSlow ) : + Timer( "SlowCallbackTimer" ), mbSlow( bBeenSlow ) + { + SetTimeout( nMS ); + Start(); + mbSlow = false; + } + virtual void Invoke() override + { + osl::Thread::wait( std::chrono::seconds(1) ); + mbSlow = true; + } +}; + +} + +void TimerTest::testSlowTimerCallback() +{ + bool bBeenSlow = false; + sal_Int32 nCount = 0; + AutoTimerCount aHighFreq(1, nCount); + SlowCallbackTimer aSlow(250, bBeenSlow); + // coverity[loop_top] - Application::Yield allows the timer to fire and toggle bBeenSlow + while (!bBeenSlow) + Application::Yield(); + // coverity[loop_top] - Application::Yield allows the timer to fire and increment nCount + while (nCount < 200) + Application::Yield(); +} + +namespace { + +class TriggerIdleFromIdle : public Idle +{ + bool* mpTriggered; + TriggerIdleFromIdle* mpOther; +public: + explicit TriggerIdleFromIdle( bool* pTriggered, TriggerIdleFromIdle* pOther ) : + Idle( "TriggerIdleFromIdle" ), mpTriggered(pTriggered), mpOther(pOther) + { + } + virtual void Invoke() override + { + Start(); + if (mpOther) + mpOther->Start(); + Application::Yield(); + if (mpTriggered) + *mpTriggered = true; + } +}; + +} + +void TimerTest::testTriggerIdleFromIdle() +{ + bool bTriggered1 = false; + bool bTriggered2 = false; + TriggerIdleFromIdle aTest2( &bTriggered2, nullptr ); + TriggerIdleFromIdle aTest1( &bTriggered1, &aTest2 ); + aTest1.Start(); + Application::Yield(); + CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered1); + CPPUNIT_ASSERT_MESSAGE("idle not triggered", bTriggered2); +} + +namespace { + +class IdleInvokedReStart : public Idle +{ + sal_Int32 &mrCount; +public: + IdleInvokedReStart( sal_Int32 &rCount ) + : Idle( "IdleInvokedReStart" ), mrCount( rCount ) + { + Start(); + } + virtual void Invoke() override + { + mrCount++; + if ( mrCount < 2 ) + Start(); + } +}; + +} + +void TimerTest::testInvokedReStart() +{ + sal_Int32 nCount = 0; + IdleInvokedReStart aIdle( nCount ); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL( sal_Int32(2), nCount ); +} + +namespace { + +class IdleSerializer : public Idle +{ + sal_uInt32 mnPosition; + sal_uInt32 &mrProcesed; +public: + IdleSerializer(const char *pDebugName, TaskPriority ePrio, + sal_uInt32 nPosition, sal_uInt32 &rProcesed) + : Idle( pDebugName ) + , mnPosition( nPosition ) + , mrProcesed( rProcesed ) + { + SetPriority(ePrio); + Start(); + } + virtual void Invoke() override + { + ++mrProcesed; + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Ignored prio", mnPosition, mrProcesed ); + } +}; + +} + +void TimerTest::testPriority() +{ + // scope, so tasks are deleted + { + // Start: 1st Idle low, 2nd high + sal_uInt32 nProcessed = 0; + IdleSerializer aLowPrioIdle("IdleSerializer LowPrio", + TaskPriority::LOWEST, 2, nProcessed); + IdleSerializer aHighPrioIdle("IdleSerializer HighPrio", + TaskPriority::HIGHEST, 1, nProcessed); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed ); + } + + { + // Start: 1st Idle high, 2nd low + sal_uInt32 nProcessed = 0; + IdleSerializer aHighPrioIdle("IdleSerializer HighPrio", + TaskPriority::HIGHEST, 1, nProcessed); + IdleSerializer aLowPrioIdle("IdleSerializer LowPrio", + TaskPriority::LOWEST, 2, nProcessed); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not all idles processed", sal_uInt32(2), nProcessed ); + } +} + +namespace { + +class TestAutoIdleRR : public AutoIdle +{ + sal_uInt32 &mrCount; + + DECL_LINK( IdleRRHdl, Timer *, void ); + +public: + TestAutoIdleRR( sal_uInt32 &rCount, + const char *pDebugName ) + : AutoIdle( pDebugName ) + , mrCount( rCount ) + { + CPPUNIT_ASSERT_EQUAL( sal_uInt32(0), mrCount ); + SetInvokeHandler( LINK( this, TestAutoIdleRR, IdleRRHdl ) ); + Start(); + } +}; + +} + +IMPL_LINK_NOARG(TestAutoIdleRR, IdleRRHdl, Timer *, void) +{ + ++mrCount; + if ( mrCount == 3 ) + Stop(); +} + +void TimerTest::testRoundRobin() +{ + sal_uInt32 nCount1 = 0, nCount2 = 0; + TestAutoIdleRR aIdle1( nCount1, "TestAutoIdleRR aIdle1" ), + aIdle2( nCount2, "TestAutoIdleRR aIdle2" ); + while ( Application::Reschedule() ) + { + CPPUNIT_ASSERT( nCount1 == nCount2 || nCount1 - 1 == nCount2 ); + CPPUNIT_ASSERT( nCount1 <= 3 ); + CPPUNIT_ASSERT( nCount2 <= 3 ); + } + CPPUNIT_ASSERT( 3 == nCount1 && 3 == nCount2 ); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(TimerTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx b/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx new file mode 100644 index 000000000..d5d0167b7 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/WidgetDefinitionReaderTest.cxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include + +#include + +namespace +{ +static OUString const gaDataUrl("/vcl/qa/cppunit/widgetdraw/data/"); + +class WidgetDefinitionReaderTest : public test::BootstrapFixtureBase +{ +private: + OUString getFullUrl(const OUString& sFileName) + { + return m_directories.getURLFromSrc(gaDataUrl) + sFileName; + } + +public: + void testRead(); + void testReadSettings(); + + CPPUNIT_TEST_SUITE(WidgetDefinitionReaderTest); + CPPUNIT_TEST(testRead); + CPPUNIT_TEST(testReadSettings); + CPPUNIT_TEST_SUITE_END(); +}; + +void WidgetDefinitionReaderTest::testReadSettings() +{ + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings1.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString(""), aDefinition.mpSettings->msCenteredTabs); + } + + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings2.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString("true"), aDefinition.mpSettings->msCenteredTabs); + } + + { + vcl::WidgetDefinition aDefinition; + vcl::WidgetDefinitionReader aReader(getFullUrl("definitionSettings3.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + CPPUNIT_ASSERT_EQUAL(OString("true"), aDefinition.mpSettings->msNoActiveTabTextRaise); + CPPUNIT_ASSERT_EQUAL(OString("false"), aDefinition.mpSettings->msCenteredTabs); + CPPUNIT_ASSERT_EQUAL(OString("0"), aDefinition.mpSettings->msListBoxEntryMargin); + CPPUNIT_ASSERT_EQUAL(OString("10"), aDefinition.mpSettings->msDefaultFontSize); + CPPUNIT_ASSERT_EQUAL(OString("16"), aDefinition.mpSettings->msTitleHeight); + CPPUNIT_ASSERT_EQUAL(OString("12"), aDefinition.mpSettings->msFloatTitleHeight); + CPPUNIT_ASSERT_EQUAL(OString("15"), + aDefinition.mpSettings->msListBoxPreviewDefaultLogicWidth); + CPPUNIT_ASSERT_EQUAL(OString("7"), + aDefinition.mpSettings->msListBoxPreviewDefaultLogicHeight); + } +} + +void WidgetDefinitionReaderTest::testRead() +{ + vcl::WidgetDefinition aDefinition; + + vcl::WidgetDefinitionReader aReader(getFullUrl("definition1.xml"), getFullUrl("")); + CPPUNIT_ASSERT(aReader.read(aDefinition)); + + CPPUNIT_ASSERT_EQUAL(OUString("123456"), aDefinition.mpStyle->maFaceColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("234567"), aDefinition.mpStyle->maCheckedColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("345678"), aDefinition.mpStyle->maLightColor.AsRGBHexString()); + + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), + aDefinition.mpStyle->maVisitedLinkColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), aDefinition.mpStyle->maToolTextColor.AsRGBHexString()); + CPPUNIT_ASSERT_EQUAL(OUString("ffffff"), aDefinition.mpStyle->maFontColor.AsRGBHexString()); + + // Pushbutton + { + ControlState eState + = ControlState::DEFAULT | ControlState::ENABLED | ControlState::ROLLOVER; + std::vector> aStates + = aDefinition.getDefinition(ControlType::Pushbutton, ControlPart::Entire) + ->getStates(ControlType::Pushbutton, ControlPart::Entire, eState, + PushButtonValue()); + + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates.size()); + + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates[0]->mpWidgetDrawActions.size()); + CPPUNIT_ASSERT_EQUAL(vcl::WidgetDrawActionType::RECTANGLE, + aStates[0]->mpWidgetDrawActions[0]->maType); + CPPUNIT_ASSERT_EQUAL(vcl::WidgetDrawActionType::LINE, + aStates[0]->mpWidgetDrawActions[1]->maType); + } + + // Radiobutton + { + std::vector> aStates + = aDefinition.getDefinition(ControlType::Radiobutton, ControlPart::Entire) + ->getStates(ControlType::Radiobutton, ControlPart::Entire, ControlState::NONE, + ImplControlValue(ButtonValue::On)); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates.size()); + CPPUNIT_ASSERT_EQUAL(size_t(2), aStates[0]->mpWidgetDrawActions.size()); + } + + { + std::vector> aStates + = aDefinition.getDefinition(ControlType::Radiobutton, ControlPart::Entire) + ->getStates(ControlType::Radiobutton, ControlPart::Entire, ControlState::NONE, + ImplControlValue(ButtonValue::Off)); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates.size()); + CPPUNIT_ASSERT_EQUAL(size_t(1), aStates[0]->mpWidgetDrawActions.size()); + } +} + +} // namespace + +CPPUNIT_TEST_SUITE_REGISTRATION(WidgetDefinitionReaderTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/widgetdraw/data/definition1.xml b/vcl/qa/cppunit/widgetdraw/data/definition1.xml new file mode 100644 index 000000000..041e8fc24 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definition1.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml new file mode 100644 index 000000000..9ca7f894f --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings1.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml new file mode 100644 index 000000000..0d6d6e111 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings2.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml b/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml new file mode 100644 index 000000000..9ad88dd54 --- /dev/null +++ b/vcl/qa/cppunit/widgetdraw/data/definitionSettings3.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/vcl/qa/unit/data/vcl-dialogs-test.txt b/vcl/qa/unit/data/vcl-dialogs-test.txt new file mode 100644 index 000000000..19fb5402c --- /dev/null +++ b/vcl/qa/unit/data/vcl-dialogs-test.txt @@ -0,0 +1,45 @@ +# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +# This file contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in vcl for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on VclBuilder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work + +vcl/ui/printerpropertiesdialog.ui +vcl/ui/printerpaperpage.ui +vcl/ui/printerdevicepage.ui +vcl/ui/printdialog.ui +vcl/ui/querydialog.ui +vcl/ui/cupspassworddialog.ui +vcl/ui/errornoprinterdialog.ui +vcl/ui/errornocontentdialog.ui +vcl/ui/printprogressdialog.ui diff --git a/vcl/qa/unit/vcl-dialogs-test.cxx b/vcl/qa/unit/vcl-dialogs-test.cxx new file mode 100644 index 000000000..fa750666e --- /dev/null +++ b/vcl/qa/unit/vcl-dialogs-test.cxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +using namespace ::com::sun::star; + +/// Test opening a dialog in vcl +class VclDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr createDialogByID(sal_uInt32 nID) override; + +public: + VclDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(VclDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +VclDialogsTest::VclDialogsTest() +{ +} + +void VclDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr VclDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void VclDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile("vcl/qa/unit/data/vcl-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(VclDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5AccessibleEventListener.cxx b/vcl/qt5/Qt5AccessibleEventListener.cxx new file mode 100644 index 000000000..621e54172 --- /dev/null +++ b/vcl/qt5/Qt5AccessibleEventListener.cxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include + +#include + +using namespace css; +using namespace css::accessibility; +using namespace css::lang; +using namespace css::uno; + +Qt5AccessibleEventListener::Qt5AccessibleEventListener(const Reference xAccessible, + Qt5AccessibleWidget* pAccessibleWidget) + : m_xAccessible(xAccessible) + , m_pAccessibleWidget(pAccessibleWidget) +{ +} + +void Qt5AccessibleEventListener::notifyEvent( + const css::accessibility::AccessibleEventObject& aEvent) +{ + QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget; + + Reference xChild; + switch (aEvent.EventId) + { + case AccessibleEventId::NAME_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::NameChanged)); + return; + case AccessibleEventId::DESCRIPTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::DescriptionChanged)); + return; + case AccessibleEventId::ACTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActionChanged)); + return; + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ActiveDescendantChanged)); + return; + case AccessibleEventId::CHILD: + { + QAccessible::Event event = QAccessible::InvalidEvent; + if (aEvent.OldValue >>= xChild) + event = QAccessible::ObjectDestroyed; + if (aEvent.NewValue >>= xChild) + event = QAccessible::ObjectCreated; + if (event != QAccessible::InvalidEvent) + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, event)); + return; + } + case AccessibleEventId::SELECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); + return; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::VisibleDataChanged)); + return; + case AccessibleEventId::TEXT_SELECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::Selection)); + return; + case AccessibleEventId::TEXT_ATTRIBUTE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::AttributeChanged)); + return; + case AccessibleEventId::TABLE_CAPTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableCaptionChanged)); + return; + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + QAccessible::updateAccessibility(new QAccessibleEvent( + pQAccessibleInterface, QAccessible::TableColumnDescriptionChanged)); + return; + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableColumnHeaderChanged)); + return; + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + QAccessible::updateAccessibility(new QAccessibleEvent( + pQAccessibleInterface, QAccessible::TableRowDescriptionChanged)); + return; + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableRowHeaderChanged)); + return; + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + case AccessibleEventId::CARET_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TableSummaryChanged)); + return; + case AccessibleEventId::SELECTION_CHANGED_ADD: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionAdd)); + return; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionRemove)); + return; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SelectionWithin)); + return; + case AccessibleEventId::PAGE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::PageChanged)); + return; + case AccessibleEventId::SECTION_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::SectionChanged)); + return; + case AccessibleEventId::TEXT_CHANGED: + case AccessibleEventId::COLUMN_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::TextColumnChanged)); + return; + case AccessibleEventId::BOUNDRECT_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::LocationChanged)); + return; + case AccessibleEventId::STATE_CHANGED: + QAccessible::updateAccessibility( + new QAccessibleEvent(pQAccessibleInterface, QAccessible::ForegroundChanged)); + return; + case AccessibleEventId::ROLE_CHANGED: + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + case AccessibleEventId::VALUE_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED: + case AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED: + case AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED: + case AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED: + case AccessibleEventId::LABEL_FOR_RELATION_CHANGED: + case AccessibleEventId::LABELED_BY_RELATION_CHANGED: + case AccessibleEventId::MEMBER_OF_RELATION_CHANGED: + case AccessibleEventId::SUB_WINDOW_OF_RELATION_CHANGED: + case AccessibleEventId::HYPERTEXT_CHANGED: + case AccessibleEventId::TABLE_MODEL_CHANGED: + case AccessibleEventId::LISTBOX_ENTRY_EXPANDED: + case AccessibleEventId::LISTBOX_ENTRY_COLLAPSED: + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + default: + SAL_WARN("vcl.qt5", "Unmapped AccessibleEventId: " << aEvent.EventId); + return; + } +} + +void Qt5AccessibleEventListener::disposing(const EventObject& /* Source */) {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5AccessibleWidget.cxx b/vcl/qt5/Qt5AccessibleWidget.cxx new file mode 100644 index 000000000..15ebdf36b --- /dev/null +++ b/vcl/qt5/Qt5AccessibleWidget.cxx @@ -0,0 +1,1267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace css; +using namespace css::accessibility; +using namespace css::beans; +using namespace css::uno; + +Qt5AccessibleWidget::Qt5AccessibleWidget(const Reference xAccessible, QObject* pObject) + : m_xAccessible(xAccessible) + , m_pObject(pObject) +{ + Reference xContext = xAccessible->getAccessibleContext(); + Reference xBroadcaster(xContext, UNO_QUERY); + if (xBroadcaster.is()) + { + Reference xListener( + new Qt5AccessibleEventListener(xAccessible, this)); + xBroadcaster->addAccessibleEventListener(xListener); + } +} + +Reference Qt5AccessibleWidget::getAccessibleContextImpl() const +{ + Reference xAc; + + if (m_xAccessible.is()) + { + try + { + xAc = m_xAccessible->getAccessibleContext(); + } + catch (css::lang::DisposedException /*ex*/) + { + SAL_WARN("vcl.qt5", "Accessible context disposed already"); + } + // sometimes getAccessibleContext throws also RuntimeException if context is no longer alive + catch (css::uno::RuntimeException /*ex*/) + { + // so let's catch it here, cuz otherwise soffice falls flat on its face + // with FatalError and nothing else + SAL_WARN("vcl.qt5", "Accessible context no longer alive"); + } + } + + return xAc; +} + +QWindow* Qt5AccessibleWidget::window() const { return nullptr; } + +int Qt5AccessibleWidget::childCount() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + return xAc->getAccessibleChildCount(); +} + +int Qt5AccessibleWidget::indexOfChild(const QAccessibleInterface* /* child */) const { return 0; } + +namespace +{ +QAccessible::Relation lcl_matchUnoRelation(short relationType) +{ + switch (relationType) + { + case AccessibleRelationType::CONTROLLER_FOR: + return QAccessible::Controller; + case AccessibleRelationType::CONTROLLED_BY: + return QAccessible::Controlled; + case AccessibleRelationType::LABEL_FOR: + return QAccessible::Label; + case AccessibleRelationType::LABELED_BY: + return QAccessible::Labelled; + case AccessibleRelationType::INVALID: + case AccessibleRelationType::CONTENT_FLOWS_FROM: + case AccessibleRelationType::CONTENT_FLOWS_TO: + case AccessibleRelationType::MEMBER_OF: + case AccessibleRelationType::SUB_WINDOW_OF: + case AccessibleRelationType::NODE_CHILD_OF: + case AccessibleRelationType::DESCRIBED_BY: + default: + SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); + return nullptr; + } +} + +short lcl_matchQtRelation(QAccessible::Relation relationType) +{ + switch (relationType) + { + case QAccessible::Controller: + return AccessibleRelationType::CONTROLLER_FOR; + case QAccessible::Controlled: + return AccessibleRelationType::CONTROLLED_BY; + case QAccessible::Label: + return AccessibleRelationType::LABEL_FOR; + case QAccessible::Labelled: + return AccessibleRelationType::LABELED_BY; + default: + SAL_WARN("vcl.qt5", "Unmatched relation: " << relationType); + } + return 0; +} + +void lcl_appendRelation(QVector>* relations, + AccessibleRelation aRelation) +{ + QAccessible::Relation aQRelation = lcl_matchUnoRelation(aRelation.RelationType); + sal_uInt32 nTargetCount = aRelation.TargetSet.getLength(); + + for (sal_uInt32 i = 0; i < nTargetCount; i++) + { + Reference xAccessible(aRelation.TargetSet[i], uno::UNO_QUERY); + relations->append( + { QAccessible::queryAccessibleInterface(new Qt5XAccessible(xAccessible)), aQRelation }); + } +} +} + +QVector> +Qt5AccessibleWidget::relations(QAccessible::Relation match) const +{ + QVector> relations; + + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return relations; + + Reference xRelationSet = xAc->getAccessibleRelationSet(); + if (xRelationSet.is()) + { + if (match == QAccessible::AllRelations) + { + int count = xRelationSet->getRelationCount(); + for (int i = 0; i < count; i++) + { + AccessibleRelation aRelation = xRelationSet->getRelation(i); + lcl_appendRelation(&relations, aRelation); + } + } + else + { + AccessibleRelation aRelation = xRelationSet->getRelation(lcl_matchQtRelation(match)); + lcl_appendRelation(&relations, aRelation); + } + } + + return relations; +} + +QAccessibleInterface* Qt5AccessibleWidget::focusChild() const +{ + /* if (m_pWindow->HasChildPathFocus()) + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(m_xAccessible->getAccessibleContext()->getAccessibleChild(index))); */ + return QAccessible::queryAccessibleInterface(object()); +} + +QRect Qt5AccessibleWidget::rect() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QRect(); + + Reference xAccessibleComponent(xAc, UNO_QUERY); + awt::Point aPoint = xAccessibleComponent->getLocation(); + awt::Size aSize = xAccessibleComponent->getSize(); + + return QRect(aPoint.X, aPoint.Y, aSize.Width, aSize.Height); +} + +QAccessibleInterface* Qt5AccessibleWidget::parent() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + return QAccessible::queryAccessibleInterface(new Qt5XAccessible(xAc->getAccessibleParent())); +} +QAccessibleInterface* Qt5AccessibleWidget::child(int index) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(xAc->getAccessibleChild(index))); +} + +QString Qt5AccessibleWidget::text(QAccessible::Text text) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + switch (text) + { + case QAccessible::Name: + return toQString(xAc->getAccessibleName()); + case QAccessible::Description: + case QAccessible::DebugDescription: + return toQString(xAc->getAccessibleDescription()); + case QAccessible::Value: + case QAccessible::Help: + case QAccessible::Accelerator: + case QAccessible::UserText: + default: + return QString("Unknown"); + } +} +QAccessible::Role Qt5AccessibleWidget::role() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QAccessible::NoRole; + + switch (xAc->getAccessibleRole()) + { + case AccessibleRole::UNKNOWN: + return QAccessible::NoRole; + + case AccessibleRole::ALERT: + return QAccessible::AlertMessage; + + case AccessibleRole::COLUMN_HEADER: + return QAccessible::ColumnHeader; + + case AccessibleRole::CANVAS: + return QAccessible::Canvas; + + case AccessibleRole::CHECK_BOX: + return QAccessible::CheckBox; + + case AccessibleRole::CHECK_MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::COLOR_CHOOSER: + return QAccessible::ColorChooser; + + case AccessibleRole::COMBO_BOX: + return QAccessible::ComboBox; + + case AccessibleRole::DATE_EDITOR: + return QAccessible::EditableText; + + case AccessibleRole::DESKTOP_ICON: + return QAccessible::Graphic; + + case AccessibleRole::DESKTOP_PANE: + case AccessibleRole::DIRECTORY_PANE: + return QAccessible::Pane; + + case AccessibleRole::DIALOG: + return QAccessible::Dialog; + + case AccessibleRole::DOCUMENT: + return QAccessible::Document; + + case AccessibleRole::EMBEDDED_OBJECT: + return QAccessible::UserRole; + + case AccessibleRole::END_NOTE: + return QAccessible::Note; + + case AccessibleRole::FILLER: + return QAccessible::Whitespace; + + case AccessibleRole::FONT_CHOOSER: + return QAccessible::UserRole; + + case AccessibleRole::FOOTER: + return QAccessible::Footer; + + case AccessibleRole::FOOTNOTE: + return QAccessible::Note; + + case AccessibleRole::FRAME: // top-level window with title bar + return QAccessible::Window; + + case AccessibleRole::GLASS_PANE: + return QAccessible::UserRole; + + case AccessibleRole::GRAPHIC: + return QAccessible::Graphic; + + case AccessibleRole::GROUP_BOX: + return QAccessible::Grouping; + + case AccessibleRole::HEADER: + return QAccessible::UserRole; + + case AccessibleRole::HEADING: + return QAccessible::Heading; + + case AccessibleRole::HYPER_LINK: + return QAccessible::Link; + + case AccessibleRole::ICON: + return QAccessible::Graphic; + + case AccessibleRole::INTERNAL_FRAME: + return QAccessible::UserRole; + + case AccessibleRole::LABEL: + return QAccessible::StaticText; + + case AccessibleRole::LAYERED_PANE: + return QAccessible::Pane; + + case AccessibleRole::LIST: + return QAccessible::List; + + case AccessibleRole::LIST_ITEM: + return QAccessible::ListItem; + + case AccessibleRole::MENU: + case AccessibleRole::MENU_BAR: + return QAccessible::MenuBar; + + case AccessibleRole::MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::OPTION_PANE: + return QAccessible::Pane; + + case AccessibleRole::PAGE_TAB: + return QAccessible::PageTab; + + case AccessibleRole::PAGE_TAB_LIST: + return QAccessible::PageTabList; + + case AccessibleRole::PANEL: + return QAccessible::Pane; + + case AccessibleRole::PARAGRAPH: + return QAccessible::Paragraph; + + case AccessibleRole::PASSWORD_TEXT: + return QAccessible::EditableText; + + case AccessibleRole::POPUP_MENU: + return QAccessible::PopupMenu; + + case AccessibleRole::PUSH_BUTTON: + return QAccessible::Button; + + case AccessibleRole::PROGRESS_BAR: + return QAccessible::ProgressBar; + + case AccessibleRole::RADIO_BUTTON: + return QAccessible::RadioButton; + + case AccessibleRole::RADIO_MENU_ITEM: + return QAccessible::MenuItem; + + case AccessibleRole::ROW_HEADER: + return QAccessible::RowHeader; + + case AccessibleRole::ROOT_PANE: + return QAccessible::Pane; + + case AccessibleRole::SCROLL_BAR: + return QAccessible::ScrollBar; + + case AccessibleRole::SCROLL_PANE: + return QAccessible::Pane; + + case AccessibleRole::SHAPE: + return QAccessible::Graphic; + + case AccessibleRole::SEPARATOR: + return QAccessible::Separator; + + case AccessibleRole::SLIDER: + return QAccessible::Slider; + + case AccessibleRole::SPIN_BOX: + return QAccessible::SpinBox; + + case AccessibleRole::SPLIT_PANE: + return QAccessible::Pane; + + case AccessibleRole::STATUS_BAR: + return QAccessible::StatusBar; + + case AccessibleRole::TABLE: + return QAccessible::Table; + + case AccessibleRole::TABLE_CELL: + return QAccessible::Cell; + + case AccessibleRole::TEXT: + return QAccessible::EditableText; + + case AccessibleRole::TEXT_FRAME: + return QAccessible::UserRole; + + case AccessibleRole::TOGGLE_BUTTON: + return QAccessible::Button; + + case AccessibleRole::TOOL_BAR: + return QAccessible::ToolBar; + + case AccessibleRole::TOOL_TIP: + return QAccessible::ToolTip; + + case AccessibleRole::TREE: + return QAccessible::Tree; + + case AccessibleRole::VIEW_PORT: + return QAccessible::UserRole; + + case AccessibleRole::BUTTON_DROPDOWN: + return QAccessible::Button; + + case AccessibleRole::BUTTON_MENU: + return QAccessible::Button; + + case AccessibleRole::CAPTION: + return QAccessible::StaticText; + + case AccessibleRole::CHART: + return QAccessible::Chart; + + case AccessibleRole::EDIT_BAR: + return QAccessible::Equation; + + case AccessibleRole::FORM: + return QAccessible::Form; + + case AccessibleRole::IMAGE_MAP: + return QAccessible::Graphic; + + case AccessibleRole::NOTE: + return QAccessible::Note; + + case AccessibleRole::RULER: + return QAccessible::UserRole; + + case AccessibleRole::SECTION: + return QAccessible::Section; + + case AccessibleRole::TREE_ITEM: + return QAccessible::TreeItem; + + case AccessibleRole::TREE_TABLE: + return QAccessible::Tree; + + case AccessibleRole::COMMENT: + return QAccessible::Note; + + case AccessibleRole::COMMENT_END: + return QAccessible::UserRole; + + case AccessibleRole::DOCUMENT_PRESENTATION: + return QAccessible::Document; + + case AccessibleRole::DOCUMENT_SPREADSHEET: + return QAccessible::Document; + + case AccessibleRole::DOCUMENT_TEXT: + return QAccessible::Document; + + case AccessibleRole::STATIC: + return QAccessible::StaticText; + + /* Ignore window objects for sub-menus, combo- and list boxes, + * which are exposed as children of their parents. + */ + case AccessibleRole::WINDOW: // top-level window without title bar + { + return QAccessible::Window; + } + } + + SAL_WARN("vcl.qt5", + "Unmapped role: " << m_xAccessible->getAccessibleContext()->getAccessibleRole()); + return QAccessible::NoRole; +} + +namespace +{ +void lcl_addState(QAccessible::State* state, sal_Int16 nState) +{ + switch (nState) + { + case AccessibleStateType::INVALID: + state->invalid = true; + break; + case AccessibleStateType::ACTIVE: + state->active = true; + break; + case AccessibleStateType::ARMED: + // No match + break; + case AccessibleStateType::BUSY: + state->busy = true; + break; + case AccessibleStateType::CHECKED: + state->checked = true; + break; + case AccessibleStateType::EDITABLE: + state->editable = true; + break; + case AccessibleStateType::ENABLED: + state->disabled = false; + break; + case AccessibleStateType::EXPANDABLE: + state->expandable = true; + break; + case AccessibleStateType::FOCUSABLE: + state->focusable = true; + break; + case AccessibleStateType::FOCUSED: + state->focused = true; + break; + case AccessibleStateType::HORIZONTAL: + // No match + break; + case AccessibleStateType::ICONIFIED: + // No match + break; + case AccessibleStateType::INDETERMINATE: + // No match + break; + case AccessibleStateType::MANAGES_DESCENDANTS: + // No match + break; + case AccessibleStateType::MODAL: + state->modal = true; + break; + case AccessibleStateType::OPAQUE: + // No match + break; + case AccessibleStateType::PRESSED: + state->pressed = true; + break; + case AccessibleStateType::RESIZABLE: + state->sizeable = true; + break; + case AccessibleStateType::SELECTABLE: + state->selectable = true; + break; + case AccessibleStateType::SELECTED: + state->selected = true; + break; + case AccessibleStateType::SENSITIVE: + // No match + break; + case AccessibleStateType::SHOWING: + // No match + break; + case AccessibleStateType::SINGLE_LINE: + // No match + break; + case AccessibleStateType::STALE: + // No match + break; + case AccessibleStateType::TRANSIENT: + // No match + break; + case AccessibleStateType::VERTICAL: + // No match + break; + case AccessibleStateType::VISIBLE: + state->invisible = false; + break; + case AccessibleStateType::DEFAULT: + // No match + break; + case AccessibleStateType::DEFUNC: + state->invalid = true; + break; + case AccessibleStateType::MULTI_SELECTABLE: + state->multiSelectable = true; + break; + default: + SAL_WARN("vcl.qt5", "Unmapped state: " << nState); + break; + } +} +} + +QAccessible::State Qt5AccessibleWidget::state() const +{ + QAccessible::State state; + + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return state; + + Reference xStateSet(xAc->getAccessibleStateSet()); + + if (!xStateSet.is()) + return state; + + Sequence aStates = xStateSet->getStates(); + + for (sal_Int32 n = 0; n < aStates.getLength(); n++) + { + lcl_addState(&state, n); + } + + return state; +} + +QColor Qt5AccessibleWidget::foregroundColor() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QColor(); + + Reference xAccessibleComponent(xAc, UNO_QUERY); + return toQColor(xAccessibleComponent->getForeground()); +} + +QColor Qt5AccessibleWidget::backgroundColor() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QColor(); + + Reference xAccessibleComponent(xAc, UNO_QUERY); + return toQColor(xAccessibleComponent->getBackground()); +} + +void* Qt5AccessibleWidget::interface_cast(QAccessible::InterfaceType t) +{ + if (t == QAccessible::ActionInterface) + return static_cast(this); + if (t == QAccessible::TextInterface) + return static_cast(this); + if (t == QAccessible::EditableTextInterface) + return static_cast(this); + if (t == QAccessible::ValueInterface) + return static_cast(this); + if (t == QAccessible::TableInterface) + return static_cast(this); + return nullptr; +} + +bool Qt5AccessibleWidget::isValid() const +{ + Reference xAc = getAccessibleContextImpl(); + return xAc.is(); +} + +QObject* Qt5AccessibleWidget::object() const { return m_pObject; } + +void Qt5AccessibleWidget::setText(QAccessible::Text /* t */, const QString& /* text */) {} + +QAccessibleInterface* Qt5AccessibleWidget::childAt(int x, int y) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference xAccessibleComponent(xAc, UNO_QUERY); + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(xAccessibleComponent->getAccessibleAtPoint(awt::Point(x, y)))); +} + +QAccessibleInterface* Qt5AccessibleWidget::customFactory(const QString& classname, QObject* object) +{ + if (classname == QLatin1String("Qt5Widget") && object && object->isWidgetType()) + { + Qt5Widget* pWidget = static_cast(object); + vcl::Window* pWindow = pWidget->frame().GetWindow(); + + if (pWindow) + return new Qt5AccessibleWidget(pWindow->GetAccessible(), object); + } + if (classname == QLatin1String("Qt5XAccessible") && object) + { + Qt5XAccessible* pXAccessible = dynamic_cast(object); + if (pXAccessible && pXAccessible->m_xAccessible.is()) + return new Qt5AccessibleWidget(pXAccessible->m_xAccessible, object); + } + + return nullptr; +} + +// QAccessibleActionInterface +QStringList Qt5AccessibleWidget::actionNames() const +{ + QStringList actionNames; + Reference xAccessibleAction(m_xAccessible, UNO_QUERY); + if (!xAccessibleAction.is()) + return actionNames; + + int count = xAccessibleAction->getAccessibleActionCount(); + for (int i = 0; i < count; i++) + { + OUString desc = xAccessibleAction->getAccessibleActionDescription(i); + actionNames.append(toQString(desc)); + } + return actionNames; +} + +void Qt5AccessibleWidget::doAction(const QString& actionName) +{ + Reference xAccessibleAction(m_xAccessible, UNO_QUERY); + if (!xAccessibleAction.is()) + return; + + int index = actionNames().indexOf(actionName); + if (index == -1) + return; + xAccessibleAction->doAccessibleAction(index); +} + +QStringList Qt5AccessibleWidget::keyBindingsForAction(const QString& actionName) const +{ + QStringList keyBindings; + Reference xAccessibleAction(m_xAccessible, UNO_QUERY); + if (!xAccessibleAction.is()) + return keyBindings; + + int index = actionNames().indexOf(actionName); + if (index == -1) + return keyBindings; + + Reference xKeyBinding + = xAccessibleAction->getAccessibleActionKeyBinding(index); + + if (!xKeyBinding.is()) + return keyBindings; + + int count = xKeyBinding->getAccessibleKeyBindingCount(); + for (int i = 0; i < count; i++) + { + Sequence keyStroke = xKeyBinding->getAccessibleKeyBinding(i); + keyBindings.append(toQString(comphelper::GetkeyBindingStrByXkeyBinding(keyStroke))); + } + return keyBindings; +} + +QAccessibleValueInterface* Qt5AccessibleWidget::valueInterface() { return nullptr; } + +QAccessibleTextInterface* Qt5AccessibleWidget::textInterface() { return nullptr; } + +// QAccessibleTextInterface +void Qt5AccessibleWidget::addSelection(int /* startOffset */, int /* endOffset */) +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::addSelection"); +} + +namespace +{ +OUString lcl_convertFontWeight(double fontWeight) +{ + if (fontWeight == awt::FontWeight::THIN || fontWeight == awt::FontWeight::ULTRALIGHT) + return "100"; + if (fontWeight == awt::FontWeight::LIGHT) + return "200"; + if (fontWeight == awt::FontWeight::SEMILIGHT) + return "300"; + if (fontWeight == awt::FontWeight::NORMAL) + return "normal"; + if (fontWeight == awt::FontWeight::SEMIBOLD) + return "500"; + if (fontWeight == awt::FontWeight::BOLD) + return "bold"; + if (fontWeight == awt::FontWeight::ULTRABOLD) + return "800"; + if (fontWeight == awt::FontWeight::BLACK) + return "900"; + + // awt::FontWeight::DONTKNOW || fontWeight == awt::FontWeight::NORMAL + return "normal"; +} +} + +QString Qt5AccessibleWidget::attributes(int offset, int* startOffset, int* endOffset) const +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (!xText.is()) + return QString(); + + // handle special values for offset the same way base class's QAccessibleTextWidget::attributes does + // (as defined in IAccessible 2: -1 -> length, -2 -> cursor position) + if (offset == -2) + offset = cursorPosition(); // currently always returns 0 + + const int nTextLength = characterCount(); + if (offset == -1 || offset == nTextLength) + offset = nTextLength - 1; + + if (offset < 0 || offset > nTextLength) + { + *startOffset = -1; + *endOffset = -1; + return QString(); + } + + const Sequence attribs + = xText->getCharacterAttributes(offset, Sequence()); + OUString aRet; + for (PropertyValue const& prop : attribs) + { + if (prop.Name == "CharFontName") + { + aRet += "font-family:" + *o3tl::doAccess(prop.Value) + ";"; + continue; + } + if (prop.Name == "CharHeight") + { + aRet += "font-size:" + OUString::number(*o3tl::doAccess(prop.Value)) + "pt;"; + continue; + } + if (prop.Name == "CharWeight") + { + aRet += "font-weight:" + lcl_convertFontWeight(*o3tl::doAccess(prop.Value)) + + ";"; + continue; + } + } + *startOffset = offset; + *endOffset = offset + 1; + return toQString(aRet); +} +int Qt5AccessibleWidget::characterCount() const +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is()) + return xText->getCharacterCount(); + return 0; +} +QRect Qt5AccessibleWidget::characterRect(int /* offset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::characterRect"); + return QRect(); +} +int Qt5AccessibleWidget::cursorPosition() const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::cursorPosition"); + return 0; +} +int Qt5AccessibleWidget::offsetAtPoint(const QPoint& /* point */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::offsetAtPoint"); + return 0; +} +void Qt5AccessibleWidget::removeSelection(int /* selectionIndex */) +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::removeSelection"); +} +void Qt5AccessibleWidget::scrollToSubstring(int startIndex, int endIndex) +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is()) + xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE); +} + +void Qt5AccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const +{ + if (!startOffset && !endOffset) + return; + + Reference xText; + if (selectionIndex == 0) + xText = Reference(m_xAccessible, UNO_QUERY); + + if (startOffset) + *startOffset = xText.is() ? xText->getSelectionStart() : 0; + if (endOffset) + *endOffset = xText.is() ? xText->getSelectionEnd() : 0; +} + +int Qt5AccessibleWidget::selectionCount() const +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is() && !xText->getSelectedText().isEmpty()) + return 1; // Only 1 selection supported atm + return 0; +} +void Qt5AccessibleWidget::setCursorPosition(int position) +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is()) + xText->setCaretPosition(position); +} +void Qt5AccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset) +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is()) + xText->setSelection(startOffset, endOffset); +} +QString Qt5AccessibleWidget::text(int startOffset, int endOffset) const +{ + Reference xText(m_xAccessible, UNO_QUERY); + if (xText.is()) + return toQString(xText->getTextRange(startOffset, endOffset)); + return QString(); +} +QString Qt5AccessibleWidget::textAfterOffset(int /* offset */, + QAccessible::TextBoundaryType /* boundaryType */, + int* /* startOffset */, int* /* endOffset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAfterOffset"); + return QString(); +} +QString Qt5AccessibleWidget::textAtOffset(int /* offset */, + QAccessible::TextBoundaryType /* boundaryType */, + int* /* startOffset */, int* /* endOffset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textAtOffset"); + return QString(); +} +QString Qt5AccessibleWidget::textBeforeOffset(int /* offset */, + QAccessible::TextBoundaryType /* boundaryType */, + int* /* startOffset */, int* /* endOffset */) const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTextInterface::textBeforeOffset"); + return QString(); +} + +// QAccessibleEditableTextInterface + +void Qt5AccessibleWidget::deleteText(int startOffset, int endOffset) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->deleteText(startOffset, endOffset); +} + +void Qt5AccessibleWidget::insertText(int offset, const QString& text) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->insertText(toOUString(text), offset); +} + +void Qt5AccessibleWidget::replaceText(int startOffset, int endOffset, const QString& text) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference xEditableText(xAc, UNO_QUERY); + if (!xEditableText.is()) + return; + xEditableText->replaceText(startOffset, endOffset, toOUString(text)); +} + +// QAccessibleValueInterface +QVariant Qt5AccessibleWidget::currentValue() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getCurrentValue() >>= aDouble; + return QVariant(aDouble); +} +QVariant Qt5AccessibleWidget::maximumValue() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getMaximumValue() >>= aDouble; + return QVariant(aDouble); +} +QVariant Qt5AccessibleWidget::minimumStepSize() const { return QVariant(); } +QVariant Qt5AccessibleWidget::minimumValue() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QVariant(); + + Reference xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return QVariant(); + double aDouble = 0; + xValue->getMinimumValue() >>= aDouble; + return QVariant(aDouble); +} +void Qt5AccessibleWidget::setCurrentValue(const QVariant& value) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return; + + Reference xValue(xAc, UNO_QUERY); + if (!xValue.is()) + return; + xValue->setCurrentValue(Any(value.toDouble())); +} + +// QAccessibleTable +QAccessibleInterface* Qt5AccessibleWidget::caption() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(xTable->getAccessibleCaption())); +} + +QAccessibleInterface* Qt5AccessibleWidget::cellAt(int row, int column) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(xTable->getAccessibleCellAt(row, column))); +} + +int Qt5AccessibleWidget::columnCount() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getAccessibleColumnCount(); +} + +QString Qt5AccessibleWidget::columnDescription(int column) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QString(); + return toQString(xTable->getAccessibleColumnDescription(column)); +} + +bool Qt5AccessibleWidget::isColumnSelected(int /* column */) const { return true; } + +bool Qt5AccessibleWidget::isRowSelected(int /* row */) const { return true; } + +void Qt5AccessibleWidget::modelChange(QAccessibleTableModelChangeEvent*) {} + +int Qt5AccessibleWidget::rowCount() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getAccessibleRowCount(); +} + +QString Qt5AccessibleWidget::rowDescription(int row) const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QString(); + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QString(); + return toQString(xTable->getAccessibleRowDescription(row)); +} + +bool Qt5AccessibleWidget::selectColumn(int column) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->selectColumn(column); +} + +bool Qt5AccessibleWidget::selectRow(int row) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->selectRow(row); +} + +int Qt5AccessibleWidget::selectedCellCount() const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCellCount"); + return 0; +} + +QList Qt5AccessibleWidget::selectedCells() const +{ + SAL_INFO("vcl.qt5", "Unsupported QAccessibleTableInterface::selectedCells"); + return QList(); +} + +int Qt5AccessibleWidget::selectedColumnCount() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getSelectedAccessibleColumns().getLength(); +} + +QList Qt5AccessibleWidget::selectedColumns() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QList(); + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QList(); + return toQList(xTable->getSelectedAccessibleColumns()); +} + +int Qt5AccessibleWidget::selectedRowCount() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return 0; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return 0; + return xTable->getSelectedAccessibleRows().getLength(); +} + +QList Qt5AccessibleWidget::selectedRows() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return QList(); + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return QList(); + return toQList(xTable->getSelectedAccessibleRows()); +} + +QAccessibleInterface* Qt5AccessibleWidget::summary() const +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return nullptr; + + Reference xTable(xAc, UNO_QUERY); + if (!xTable.is()) + return nullptr; + return QAccessible::queryAccessibleInterface( + new Qt5XAccessible(xTable->getAccessibleSummary())); +} + +bool Qt5AccessibleWidget::unselectColumn(int column) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->unselectColumn(column); +} + +bool Qt5AccessibleWidget::unselectRow(int row) +{ + Reference xAc = getAccessibleContextImpl(); + if (!xAc.is()) + return false; + + Reference xTableSelection(xAc, UNO_QUERY); + if (!xTableSelection.is()) + return false; + return xTableSelection->unselectRow(row); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Bitmap.cxx b/vcl/qt5/Qt5Bitmap.cxx new file mode 100644 index 000000000..01c6ebc4d --- /dev/null +++ b/vcl/qt5/Qt5Bitmap.cxx @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +Qt5Bitmap::Qt5Bitmap() {} + +Qt5Bitmap::Qt5Bitmap(const QImage& rImage) { m_pImage.reset(new QImage(rImage)); } + +bool Qt5Bitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal) +{ + assert( + (nBitCount == 1 || nBitCount == 4 || nBitCount == 8 || nBitCount == 24 || nBitCount == 32) + && "Unsupported BitCount!"); + + if (nBitCount == 1) + assert(2 >= rPal.GetEntryCount()); + if (nBitCount == 4) + assert(16 >= rPal.GetEntryCount()); + if (nBitCount == 8) + assert(256 >= rPal.GetEntryCount()); + + if (nBitCount == 4) + { + m_pImage.reset(); + m_aSize = rSize; + bool bFail = o3tl::checked_multiply(rSize.Width(), nBitCount, m_nScanline); + if (bFail) + { + SAL_WARN("vcl.gdi", "checked multiply failed"); + return false; + } + m_nScanline = AlignedWidth4Bytes(m_nScanline); + sal_uInt8* pBuffer = nullptr; + if (0 != m_nScanline && 0 != rSize.Height()) + pBuffer = new sal_uInt8[m_nScanline * rSize.Height()]; + m_pBuffer.reset(pBuffer); + } + else + { + m_pImage.reset(new QImage(toQSize(rSize), getBitFormat(nBitCount))); + m_pImage->fill(Qt::transparent); + m_pBuffer.reset(); + } + m_aPalette = rPal; + + auto count = rPal.GetEntryCount(); + if (nBitCount != 4 && count && m_pImage) + { + QVector aColorTable(count); + for (unsigned i = 0; i < count; ++i) + aColorTable[i] = qRgb(rPal[i].GetRed(), rPal[i].GetGreen(), rPal[i].GetBlue()); + m_pImage->setColorTable(aColorTable); + } + return true; +} + +bool Qt5Bitmap::Create(const SalBitmap& rSalBmp) +{ + const Qt5Bitmap* pBitmap = static_cast(&rSalBmp); + if (pBitmap->m_pImage) + { + m_pImage.reset(new QImage(*pBitmap->m_pImage)); + m_pBuffer.reset(); + } + else + { + m_aSize = pBitmap->m_aSize; + m_nScanline = pBitmap->m_nScanline; + sal_uInt8* pBuffer = nullptr; + if (0 != m_nScanline && 0 != m_aSize.Height()) + { + sal_uInt32 nSize = m_nScanline * m_aSize.Height(); + pBuffer = new sal_uInt8[nSize]; + memcpy(pBuffer, pBitmap->m_pBuffer.get(), nSize); + } + m_pBuffer.reset(pBuffer); + m_pImage.reset(); + } + m_aPalette = pBitmap->m_aPalette; + return true; +} + +bool Qt5Bitmap::Create(const SalBitmap& rSalBmp, SalGraphics* pSalGraphics) +{ + const Qt5Bitmap* pBitmap = static_cast(&rSalBmp); + Qt5Graphics* pGraphics = static_cast(pSalGraphics); + QImage* pImage = pGraphics->m_pQImage; + m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(pImage->format()))); + m_pBuffer.reset(); + return true; +} + +bool Qt5Bitmap::Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount) +{ + assert((nNewBitCount == 1 || nNewBitCount == 4 || nNewBitCount == 8 || nNewBitCount == 24 + || nNewBitCount == 32) + && "Unsupported BitCount!"); + + const Qt5Bitmap* pBitmap = static_cast(&rSalBmp); + if (pBitmap->m_pBuffer) + { + if (nNewBitCount != 32) + return false; + + // convert 4bit indexed palette to 32bit ARGB + m_pImage.reset(new QImage(pBitmap->m_aSize.Width(), pBitmap->m_aSize.Height(), + getBitFormat(nNewBitCount))); + m_pImage->fill(Qt::transparent); + + // prepare a whole palette + const BitmapPalette& rPal = pBitmap->m_aPalette; + QVector colorTable(16); + int i = 0, maxEntry = pBitmap->m_aPalette.GetEntryCount(); + assert(maxEntry <= 16 && maxEntry >= 0); + for (; i < maxEntry; ++i) + colorTable[i] = qRgb(rPal[i].GetRed(), rPal[i].GetGreen(), rPal[i].GetBlue()); + for (; i < 16; ++i) + colorTable[i] = qRgb(0, 0, 0); + + sal_uInt32* image_data = reinterpret_cast(m_pImage->bits()); + sal_uInt8* buffer_data_pos = pBitmap->m_pBuffer.get(); + sal_uInt32 nWidth = pBitmap->m_aSize.Height() / 2; + bool isOdd(0 != pBitmap->m_aSize.Height() % 2); + + for (long h = 0; h < pBitmap->m_aSize.Height(); ++h) + { + sal_uInt8* buffer_data = buffer_data_pos; + buffer_data_pos += pBitmap->m_nScanline; + for (sal_uInt32 w = 0; w < nWidth; ++w) + { + *image_data = static_cast(colorTable.at(*buffer_data >> 4)); + ++image_data; + *image_data = static_cast(colorTable.at(*buffer_data & 0xF)); + ++image_data; + ++buffer_data; + } + if (isOdd) + { + *image_data = static_cast(colorTable.at(*buffer_data >> 4)); + ++image_data; + } + } + } + else + m_pImage.reset(new QImage(pBitmap->m_pImage->convertToFormat(getBitFormat(nNewBitCount)))); + m_pBuffer.reset(); + return true; +} + +bool Qt5Bitmap::Create(const css::uno::Reference& /*rBitmapCanvas*/, + Size& /*rSize*/, bool /*bMask*/) +{ + return false; +} + +void Qt5Bitmap::Destroy() +{ + m_pImage.reset(); + m_pBuffer.reset(); +} + +Size Qt5Bitmap::GetSize() const +{ + if (m_pBuffer) + return m_aSize; + else if (m_pImage) + return toSize(m_pImage->size()); + return Size(); +} + +sal_uInt16 Qt5Bitmap::GetBitCount() const +{ + if (m_pBuffer) + return 4; + else if (m_pImage) + return getFormatBits(m_pImage->format()); + return 0; +} + +BitmapBuffer* Qt5Bitmap::AcquireBuffer(BitmapAccessMode /*nMode*/) +{ + static const BitmapPalette aEmptyPalette; + + if (!(m_pImage || m_pBuffer)) + return nullptr; + + BitmapBuffer* pBuffer = new BitmapBuffer; + + if (m_pBuffer) + { + pBuffer->mnWidth = m_aSize.Width(); + pBuffer->mnHeight = m_aSize.Height(); + pBuffer->mnBitCount = 4; + pBuffer->mpBits = m_pBuffer.get(); + pBuffer->mnScanlineSize = m_nScanline; + } + else + { + pBuffer->mnWidth = m_pImage->width(); + pBuffer->mnHeight = m_pImage->height(); + pBuffer->mnBitCount = getFormatBits(m_pImage->format()); + pBuffer->mpBits = m_pImage->bits(); + pBuffer->mnScanlineSize = m_pImage->bytesPerLine(); + } + + switch (pBuffer->mnBitCount) + { + case 1: + pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal | ScanlineFormat::TopDown; + pBuffer->maPalette = m_aPalette; + break; + case 4: + pBuffer->mnFormat = ScanlineFormat::N4BitMsnPal | ScanlineFormat::TopDown; + pBuffer->maPalette = m_aPalette; + break; + case 8: + pBuffer->mnFormat = ScanlineFormat::N8BitPal | ScanlineFormat::TopDown; + pBuffer->maPalette = m_aPalette; + break; + case 24: + pBuffer->mnFormat = ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown; + pBuffer->maPalette = aEmptyPalette; + break; + case 32: + { +#ifdef OSL_BIGENDIAN + pBuffer->mnFormat = ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown; +#else + pBuffer->mnFormat = ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown; +#endif + pBuffer->maPalette = aEmptyPalette; + break; + } + default: + assert(false); + } + + return pBuffer; +} + +void Qt5Bitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) +{ + m_aPalette = pBuffer->maPalette; + auto count = m_aPalette.GetEntryCount(); + if (pBuffer->mnBitCount != 4 && count) + { + QVector aColorTable(count); + for (unsigned i = 0; i < count; ++i) + aColorTable[i] + = qRgb(m_aPalette[i].GetRed(), m_aPalette[i].GetGreen(), m_aPalette[i].GetBlue()); + m_pImage->setColorTable(aColorTable); + } + delete pBuffer; + if (nMode == BitmapAccessMode::Write) + InvalidateChecksum(); +} + +bool Qt5Bitmap::GetSystemData(BitmapSystemData& /*rData*/) { return false; } + +bool Qt5Bitmap::ScalingSupported() const { return false; } + +bool Qt5Bitmap::Scale(const double& /*rScaleX*/, const double& /*rScaleY*/, + BmpScaleFlag /*nScaleFlag*/) +{ + return false; +} + +bool Qt5Bitmap::Replace(const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, + sal_uInt8 /*nTol*/) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Clipboard.cxx b/vcl/qt5/Qt5Clipboard.cxx new file mode 100644 index 000000000..8720cfe44 --- /dev/null +++ b/vcl/qt5/Qt5Clipboard.cxx @@ -0,0 +1,243 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +Qt5Clipboard::Qt5Clipboard(const OUString& aModeString, const QClipboard::Mode aMode) + : cppu::WeakComponentImplHelper(m_aMutex) + , m_aClipboardName(aModeString) + , m_aClipboardMode(aMode) + , m_bOwnClipboardChange(false) + , m_bDoClear(false) +{ + assert(isSupported(m_aClipboardMode)); + // DirectConnection guarantees the changed slot runs in the same thread as the QClipboard + connect(QApplication::clipboard(), &QClipboard::changed, this, &Qt5Clipboard::handleChanged, + Qt::DirectConnection); + + // explicitly queue an event, so we can eventually ignore it + connect(this, &Qt5Clipboard::clearClipboard, this, &Qt5Clipboard::handleClearClipboard, + Qt::QueuedConnection); +} + +css::uno::Reference Qt5Clipboard::create(const OUString& aModeString) +{ + static const std::map aNameToClipboardMap + = { { "CLIPBOARD", QClipboard::Clipboard }, { "PRIMARY", QClipboard::Selection } }; + + assert(QApplication::clipboard()->thread() == qApp->thread()); + + auto iter = aNameToClipboardMap.find(aModeString); + if (iter != aNameToClipboardMap.end() && isSupported(iter->second)) + return static_cast(new Qt5Clipboard(aModeString, iter->second)); + SAL_WARN("vcl.qt5", "Ignoring unrecognized clipboard type: '" << aModeString << "'"); + return css::uno::Reference(); +} + +void Qt5Clipboard::flushClipboard() +{ + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!isOwner(m_aClipboardMode)) + return; + + QClipboard* pClipboard = QApplication::clipboard(); + const Qt5MimeData* pQt5MimeData + = dynamic_cast(pClipboard->mimeData(m_aClipboardMode)); + assert(pQt5MimeData); + + QMimeData* pMimeCopy = nullptr; + if (pQt5MimeData && pQt5MimeData->deepCopy(&pMimeCopy)) + { + m_bOwnClipboardChange = true; + pClipboard->setMimeData(pMimeCopy, m_aClipboardMode); + m_bOwnClipboardChange = false; + } + }); +} + +css::uno::Reference Qt5Clipboard::getContents() +{ + osl::MutexGuard aGuard(m_aMutex); + + // if we're the owner, we might have the XTransferable from setContents. but + // maybe a non-LO clipboard change from within LO, like some C'n'P in the + // QFileDialog, might have invalidated m_aContents, so we need to check it too. + if (isOwner(m_aClipboardMode) && m_aContents.is()) + return m_aContents; + + // check if we can still use the shared Qt5ClipboardTransferable + const QMimeData* pMimeData = QApplication::clipboard()->mimeData(m_aClipboardMode); + if (m_aContents.is()) + { + const auto* pTrans = dynamic_cast(m_aContents.get()); + assert(pTrans); + if (pTrans && pTrans->mimeData() == pMimeData) + return m_aContents; + } + + m_aContents = new Qt5ClipboardTransferable(m_aClipboardMode, pMimeData); + return m_aContents; +} + +void Qt5Clipboard::handleClearClipboard() +{ + if (!m_bDoClear) + return; + QApplication::clipboard()->clear(m_aClipboardMode); +} + +void Qt5Clipboard::setContents( + const css::uno::Reference& xTrans, + const css::uno::Reference& xClipboardOwner) +{ + // it's actually possible to get a non-empty xTrans and an empty xClipboardOwner! + osl::ClearableMutexGuard aGuard(m_aMutex); + + css::uno::Reference xOldOwner(m_aOwner); + css::uno::Reference xOldContents(m_aContents); + m_aContents = xTrans; + m_aOwner = xClipboardOwner; + + m_bDoClear = !m_aContents.is(); + if (!m_bDoClear) + { + m_bOwnClipboardChange = true; + QApplication::clipboard()->setMimeData(new Qt5MimeData(m_aContents), m_aClipboardMode); + m_bOwnClipboardChange = false; + } + else + { + assert(!m_aOwner.is()); + Q_EMIT clearClipboard(); + } + + aGuard.clear(); + + // we have to notify only an owner change, since handleChanged can't + // access the previous owner anymore and can just handle lost ownership. + if (xOldOwner.is() && xOldOwner != xClipboardOwner) + xOldOwner->lostOwnership(this, xOldContents); +} + +void Qt5Clipboard::handleChanged(QClipboard::Mode aMode) +{ + if (aMode != m_aClipboardMode) + return; + + osl::ClearableMutexGuard aGuard(m_aMutex); + + css::uno::Reference xOldOwner(m_aOwner); + css::uno::Reference xOldContents(m_aContents); + // ownership change from LO POV is handled in setContents + if (!m_bOwnClipboardChange) + { + m_aContents.clear(); + m_aOwner.clear(); + } + + std::vector> aListeners( + m_aListeners); + css::datatransfer::clipboard::ClipboardEvent aEv; + aEv.Contents = getContents(); + + aGuard.clear(); + + if (!m_bOwnClipboardChange && xOldOwner.is()) + xOldOwner->lostOwnership(this, xOldContents); + for (auto const& listener : aListeners) + listener->changedContents(aEv); +} + +OUString Qt5Clipboard::getImplementationName() { return "com.sun.star.datatransfer.Qt5Clipboard"; } + +css::uno::Sequence Qt5Clipboard::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.clipboard.SystemClipboard" }; +} + +sal_Bool Qt5Clipboard::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +OUString Qt5Clipboard::getName() { return m_aClipboardName; } + +sal_Int8 Qt5Clipboard::getRenderingCapabilities() { return 0; } + +void Qt5Clipboard::addClipboardListener( + const css::uno::Reference& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + m_aListeners.push_back(listener); +} + +void Qt5Clipboard::removeClipboardListener( + const css::uno::Reference& listener) +{ + osl::MutexGuard aGuard(m_aMutex); + m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), listener), + m_aListeners.end()); +} + +bool Qt5Clipboard::isSupported(const QClipboard::Mode aMode) +{ + const QClipboard* pClipboard = QApplication::clipboard(); + switch (aMode) + { + case QClipboard::Selection: + return pClipboard->supportsSelection(); + + case QClipboard::FindBuffer: + return pClipboard->supportsFindBuffer(); + + case QClipboard::Clipboard: + return true; + } + return false; +} + +bool Qt5Clipboard::isOwner(const QClipboard::Mode aMode) +{ + if (!isSupported(aMode)) + return false; + + const QClipboard* pClipboard = QApplication::clipboard(); + switch (aMode) + { + case QClipboard::Selection: + return pClipboard->ownsSelection(); + + case QClipboard::FindBuffer: + return pClipboard->ownsFindBuffer(); + + case QClipboard::Clipboard: + return pClipboard->ownsClipboard(); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Data.cxx b/vcl/qt5/Qt5Data.cxx new file mode 100644 index 000000000..c50f8c57d --- /dev/null +++ b/vcl/qt5/Qt5Data.cxx @@ -0,0 +1,334 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +Qt5Data::Qt5Data(SalInstance* pInstance) + : GenericUnixSalData(SAL_DATA_QT5, pInstance) +{ + ImplSVData* pSVData = ImplGetSVData(); + + pSVData->maNWFData.mbDockingAreaSeparateTB = true; + pSVData->maNWFData.mbFlatMenu = true; + pSVData->maNWFData.mbRolloverMenubar = true; + pSVData->maNWFData.mbNoFocusRects = true; + pSVData->maNWFData.mbNoFocusRectsForFlatButtons = true; + + QStyle* style = QApplication::style(); + pSVData->maNWFData.mnMenuFormatBorderX = style->pixelMetric(QStyle::PM_MenuPanelWidth) + + style->pixelMetric(QStyle::PM_MenuHMargin); + pSVData->maNWFData.mnMenuFormatBorderY = style->pixelMetric(QStyle::PM_MenuPanelWidth) + + style->pixelMetric(QStyle::PM_MenuVMargin); +} + +// outline dtor b/c of FreetypeManager incomplete type +Qt5Data::~Qt5Data() {} + +static QCursor* getQCursorFromXBM(const unsigned char* pBitmap, const unsigned char* pMask, + int nWidth, int nHeight, int nXHot, int nYHot) +{ + QBitmap aPixmap = QBitmap::fromData(QSize(nWidth, nHeight), pBitmap); + QBitmap aMask = QBitmap::fromData(QSize(nWidth, nHeight), pMask); + return new QCursor(aPixmap, aMask, nXHot, nYHot); +} + +#define MAKE_CURSOR(vcl_name, name) \ + case vcl_name: \ + pCursor = getQCursorFromXBM(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, qt_enum) \ + case vcl_name: \ + pCursor = new QCursor(qt_enum); \ + break + +QCursor& Qt5Data::getCursor(PointerStyle ePointerStyle) +{ + if (!m_aCursors[ePointerStyle]) + { + QCursor* pCursor = nullptr; + + switch (ePointerStyle) + { + MAP_BUILTIN(PointerStyle::Arrow, Qt::ArrowCursor); + MAP_BUILTIN(PointerStyle::Text, Qt::IBeamCursor); + MAP_BUILTIN(PointerStyle::Help, Qt::WhatsThisCursor); + MAP_BUILTIN(PointerStyle::Cross, Qt::CrossCursor); + MAP_BUILTIN(PointerStyle::Wait, Qt::WaitCursor); + MAP_BUILTIN(PointerStyle::NSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::SSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WSize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::ESize, Qt::SizeHorCursor); + + MAP_BUILTIN(PointerStyle::NWSize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::NESize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::SWSize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::SESize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::WindowNSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WindowSSize, Qt::SizeVerCursor); + MAP_BUILTIN(PointerStyle::WindowWSize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::WindowESize, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::WindowNWSize, Qt::SizeFDiagCursor); + MAP_BUILTIN(PointerStyle::WindowNESize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::WindowSWSize, Qt::SizeBDiagCursor); + MAP_BUILTIN(PointerStyle::WindowSESize, Qt::SizeFDiagCursor); + + MAP_BUILTIN(PointerStyle::HSizeBar, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::VSizeBar, Qt::SizeVerCursor); + + MAP_BUILTIN(PointerStyle::RefHand, Qt::OpenHandCursor); + MAP_BUILTIN(PointerStyle::Hand, Qt::OpenHandCursor); +#if 0 + MAP_BUILTIN( PointerStyle::Pen, GDK_PENCIL ); +#endif + MAP_BUILTIN(PointerStyle::HSplit, Qt::SizeHorCursor); + MAP_BUILTIN(PointerStyle::VSplit, Qt::SizeVerCursor); + + MAP_BUILTIN(PointerStyle::Move, Qt::SizeAllCursor); + + MAP_BUILTIN(PointerStyle::Null, Qt::BlankCursor); + MAKE_CURSOR(PointerStyle::Magnify, magnify_); + MAKE_CURSOR(PointerStyle::Fill, fill_); + MAKE_CURSOR(PointerStyle::MoveData, movedata_); + MAKE_CURSOR(PointerStyle::CopyData, copydata_); + MAKE_CURSOR(PointerStyle::MoveFile, movefile_); + MAKE_CURSOR(PointerStyle::CopyFile, copyfile_); + MAKE_CURSOR(PointerStyle::MoveFiles, movefiles_); + MAKE_CURSOR(PointerStyle::CopyFiles, copyfiles_); + MAKE_CURSOR(PointerStyle::NotAllowed, nodrop_); + MAKE_CURSOR(PointerStyle::Rotate, rotate_); + MAKE_CURSOR(PointerStyle::HShear, hshear_); + MAKE_CURSOR(PointerStyle::VShear, vshear_); + MAKE_CURSOR(PointerStyle::DrawLine, drawline_); + MAKE_CURSOR(PointerStyle::DrawRect, drawrect_); + MAKE_CURSOR(PointerStyle::DrawPolygon, drawpolygon_); + MAKE_CURSOR(PointerStyle::DrawBezier, drawbezier_); + MAKE_CURSOR(PointerStyle::DrawArc, drawarc_); + MAKE_CURSOR(PointerStyle::DrawPie, drawpie_); + MAKE_CURSOR(PointerStyle::DrawCircleCut, drawcirclecut_); + MAKE_CURSOR(PointerStyle::DrawEllipse, drawellipse_); + MAKE_CURSOR(PointerStyle::DrawConnect, drawconnect_); + MAKE_CURSOR(PointerStyle::DrawText, drawtext_); + MAKE_CURSOR(PointerStyle::Mirror, mirror_); + MAKE_CURSOR(PointerStyle::Crook, crook_); + MAKE_CURSOR(PointerStyle::Crop, crop_); + MAKE_CURSOR(PointerStyle::MovePoint, movepoint_); + MAKE_CURSOR(PointerStyle::MoveBezierWeight, movebezierweight_); + MAKE_CURSOR(PointerStyle::DrawFreehand, drawfreehand_); + MAKE_CURSOR(PointerStyle::DrawCaption, drawcaption_); + MAKE_CURSOR(PointerStyle::LinkData, linkdata_); + MAKE_CURSOR(PointerStyle::MoveDataLink, movedlnk_); + MAKE_CURSOR(PointerStyle::CopyDataLink, copydlnk_); + MAKE_CURSOR(PointerStyle::LinkFile, linkfile_); + MAKE_CURSOR(PointerStyle::MoveFileLink, moveflnk_); + MAKE_CURSOR(PointerStyle::CopyFileLink, copyflnk_); + MAKE_CURSOR(PointerStyle::Chart, chart_); + MAKE_CURSOR(PointerStyle::Detective, detective_); + MAKE_CURSOR(PointerStyle::PivotCol, pivotcol_); + MAKE_CURSOR(PointerStyle::PivotRow, pivotrow_); + MAKE_CURSOR(PointerStyle::PivotField, pivotfld_); + MAKE_CURSOR(PointerStyle::PivotDelete, pivotdel_); + MAKE_CURSOR(PointerStyle::Chain, chain_); + MAKE_CURSOR(PointerStyle::ChainNotAllowed, chainnot_); + MAKE_CURSOR(PointerStyle::AutoScrollN, asn_); + MAKE_CURSOR(PointerStyle::AutoScrollS, ass_); + MAKE_CURSOR(PointerStyle::AutoScrollW, asw_); + MAKE_CURSOR(PointerStyle::AutoScrollE, ase_); + MAKE_CURSOR(PointerStyle::AutoScrollNW, asnw_); + MAKE_CURSOR(PointerStyle::AutoScrollNE, asne_); + MAKE_CURSOR(PointerStyle::AutoScrollSW, assw_); + MAKE_CURSOR(PointerStyle::AutoScrollSE, asse_); + MAKE_CURSOR(PointerStyle::AutoScrollNS, asns_); + MAKE_CURSOR(PointerStyle::AutoScrollWE, aswe_); + MAKE_CURSOR(PointerStyle::AutoScrollNSWE, asnswe_); + MAKE_CURSOR(PointerStyle::TextVertical, vertcurs_); + + MAKE_CURSOR(PointerStyle::TabSelectS, tblsels_); + MAKE_CURSOR(PointerStyle::TabSelectE, tblsele_); + MAKE_CURSOR(PointerStyle::TabSelectSE, tblselse_); + MAKE_CURSOR(PointerStyle::TabSelectW, tblselw_); + MAKE_CURSOR(PointerStyle::TabSelectSW, tblselsw_); + + MAKE_CURSOR(PointerStyle::HideWhitespace, hidewhitespace_); + MAKE_CURSOR(PointerStyle::ShowWhitespace, showwhitespace_); + default: + break; + } + if (!pCursor) + { + pCursor = new QCursor(Qt::ArrowCursor); + SAL_WARN("vcl.qt5", + "pointer " << static_cast(ePointerStyle) << " not implemented"); + } + + m_aCursors[ePointerStyle].reset(pCursor); + } + + return *m_aCursors[ePointerStyle]; +} + +void Qt5Data::ErrorTrapPush() {} + +bool Qt5Data::ErrorTrapPop(bool /*bIgnoreError*/) { return false; } + +bool Qt5Data::noNativeControls() +{ + static const bool bNoNative + = ((nullptr != getenv("SAL_VCL_QT5_NO_NATIVE")) && (nullptr != ImplGetSVData()) + && ImplGetSVData()->maAppData.mxToolkitName + && ImplGetSVData()->maAppData.mxToolkitName->match("qt5")); + return bNoNative; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5DragAndDrop.cxx b/vcl/qt5/Qt5DragAndDrop.cxx new file mode 100644 index 000000000..615b5d1f7 --- /dev/null +++ b/vcl/qt5/Qt5DragAndDrop.cxx @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace com::sun::star; + +Qt5DragSource::~Qt5DragSource() {} + +void Qt5DragSource::deinitialize() { m_pFrame = nullptr; } + +sal_Bool Qt5DragSource::isDragImageSupported() { return true; } + +sal_Int32 Qt5DragSource::getDefaultCursor(sal_Int8) { return 0; } + +void Qt5DragSource::initialize(const css::uno::Sequence& rArguments) +{ + if (rArguments.getLength() < 2) + { + throw uno::RuntimeException("DragSource::initialize: Cannot install window event handler", + static_cast(this)); + } + + sal_IntPtr nFrame = 0; + rArguments.getConstArray()[1] >>= nFrame; + + if (!nFrame) + { + throw uno::RuntimeException("DragSource::initialize: missing SalFrame", + static_cast(this)); + } + + m_pFrame = reinterpret_cast(nFrame); + m_pFrame->registerDragSource(this); +} + +void Qt5DragSource::startDrag( + const datatransfer::dnd::DragGestureEvent& /*rEvent*/, sal_Int8 sourceActions, + sal_Int32 /*cursor*/, sal_Int32 /*image*/, + const css::uno::Reference& rTrans, + const css::uno::Reference& rListener) +{ + m_xListener = rListener; + + if (m_pFrame) + { + QDrag* drag = new QDrag(m_pFrame->GetQWidget()); + drag->setMimeData(new Qt5MimeData(rTrans)); + // just a reminder that exec starts a nested event loop, so everything after + // this call is just executed, after D'n'D has finished! + drag->exec(toQtDropActions(sourceActions), getPreferredDropAction(sourceActions)); + } + + // the drop will eventually call fire_dragEnd, which will clear the listener. + // if D'n'D ends without success, we just get a leave event without any indicator, + // but the event loop will be terminated, so we have to try to inform the source of + // a failure in any way. + fire_dragEnd(datatransfer::dnd::DNDConstants::ACTION_NONE, false); +} + +void Qt5DragSource::fire_dragEnd(sal_Int8 nAction, bool bDropSuccessful) +{ + if (!m_xListener.is()) + return; + + datatransfer::dnd::DragSourceDropEvent aEv; + aEv.DropAction = nAction; + aEv.DropSuccess = bDropSuccessful; + + auto xListener = m_xListener; + m_xListener.clear(); + xListener->dragDropEnd(aEv); +} + +OUString SAL_CALL Qt5DragSource::getImplementationName() +{ + return "com.sun.star.datatransfer.dnd.VclQt5DragSource"; +} + +sal_Bool SAL_CALL Qt5DragSource::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence SAL_CALL Qt5DragSource::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.dnd.Qt5DragSource" }; +} + +Qt5DropTarget::Qt5DropTarget() + : WeakComponentImplHelper(m_aMutex) + , m_pFrame(nullptr) + , m_bActive(false) + , m_nDefaultActions(0) +{ +} + +OUString SAL_CALL Qt5DropTarget::getImplementationName() +{ + return "com.sun.star.datatransfer.dnd.VclQt5DropTarget"; +} + +sal_Bool SAL_CALL Qt5DropTarget::supportsService(OUString const& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence SAL_CALL Qt5DropTarget::getSupportedServiceNames() +{ + return { "com.sun.star.datatransfer.dnd.Qt5DropTarget" }; +} + +Qt5DropTarget::~Qt5DropTarget() {} + +void Qt5DropTarget::deinitialize() +{ + m_pFrame = nullptr; + m_bActive = false; +} + +void Qt5DropTarget::initialize(const uno::Sequence& rArguments) +{ + if (rArguments.getLength() < 2) + { + throw uno::RuntimeException("DropTarget::initialize: Cannot install window event handler", + static_cast(this)); + } + + sal_IntPtr nFrame = 0; + rArguments.getConstArray()[1] >>= nFrame; + + if (!nFrame) + { + throw uno::RuntimeException("DropTarget::initialize: missing SalFrame", + static_cast(this)); + } + + m_nDropAction = datatransfer::dnd::DNDConstants::ACTION_NONE; + + m_pFrame = reinterpret_cast(nFrame); + m_pFrame->registerDropTarget(this); + m_bActive = true; +} + +void Qt5DropTarget::addDropTargetListener( + const uno::Reference& xListener) +{ + ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); + + m_aListeners.push_back(xListener); +} + +void Qt5DropTarget::removeDropTargetListener( + const uno::Reference& xListener) +{ + ::osl::Guard<::osl::Mutex> aGuard(m_aMutex); + + m_aListeners.erase(std::remove(m_aListeners.begin(), m_aListeners.end(), xListener), + m_aListeners.end()); +} + +sal_Bool Qt5DropTarget::isActive() { return m_bActive; } + +void Qt5DropTarget::setActive(sal_Bool bActive) { m_bActive = bActive; } + +sal_Int8 Qt5DropTarget::getDefaultActions() { return m_nDefaultActions; } + +void Qt5DropTarget::setDefaultActions(sal_Int8 nDefaultActions) +{ + m_nDefaultActions = nDefaultActions; +} + +void Qt5DropTarget::fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + { + listener->dragEnter(dtde); + } +} + +void Qt5DropTarget::fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->dragOver(dtde); +} + +void Qt5DropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) +{ + m_bDropSuccessful = true; + + osl::ClearableGuard aGuard(m_aMutex); + std::vector> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->drop(dtde); +} + +void Qt5DropTarget::fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte) +{ + osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex); + std::vector> aListeners( + m_aListeners); + aGuard.clear(); + + for (auto const& listener : aListeners) + listener->dragExit(dte); +} + +void Qt5DropTarget::acceptDrag(sal_Int8 dragOperation) { m_nDropAction = dragOperation; } + +void Qt5DropTarget::rejectDrag() { m_nDropAction = 0; } + +void Qt5DropTarget::acceptDrop(sal_Int8 dropOperation) { m_nDropAction = dropOperation; } + +void Qt5DropTarget::rejectDrop() { m_nDropAction = 0; } + +void Qt5DropTarget::dropComplete(sal_Bool success) +{ + m_bDropSuccessful = (m_bDropSuccessful && success); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FilePicker.cxx b/vcl/qt5/Qt5FilePicker.cxx new file mode 100644 index 000000000..d648a5d94 --- /dev/null +++ b/vcl/qt5/Qt5FilePicker.cxx @@ -0,0 +1,945 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ui::dialogs; +using namespace ::com::sun::star::ui::dialogs::TemplateDescription; +using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds; +using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + +namespace +{ +uno::Sequence FilePicker_getSupportedServiceNames() +{ + return { "com.sun.star.ui.dialogs.FilePicker", "com.sun.star.ui.dialogs.SystemFilePicker", + "com.sun.star.ui.dialogs.Qt5FilePicker" }; +} +} + +Qt5FilePicker::Qt5FilePicker(css::uno::Reference const& context, + QFileDialog::FileMode eMode, bool bUseNative) + : Qt5FilePicker_Base(m_aHelperMutex) + , m_context(context) + , m_bIsFolderPicker(eMode == QFileDialog::Directory) + , m_pParentWidget(nullptr) + , m_pFileDialog(new QFileDialog(nullptr, {}, QDir::homePath())) + , m_pExtraControls(new QWidget()) +{ + m_pFileDialog->setOption(QFileDialog::DontUseNativeDialog, !bUseNative); + + m_pFileDialog->setFileMode(eMode); + m_pFileDialog->setWindowModality(Qt::ApplicationModal); + + if (m_bIsFolderPicker) + { + m_pFileDialog->setOption(QFileDialog::ShowDirsOnly, true); + m_pFileDialog->setWindowTitle(toQString(VclResId(STR_FPICKER_FOLDER_DEFAULT_TITLE))); + } + + m_pLayout = dynamic_cast(m_pFileDialog->layout()); + + setMultiSelectionMode(false); + + // XFilePickerListener notifications + connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, + SLOT(filterSelected(const QString&))); + connect(m_pFileDialog.get(), SIGNAL(currentChanged(const QString&)), this, + SLOT(currentChanged(const QString&))); + + // update automatic file extension when filter is changed + connect(m_pFileDialog.get(), SIGNAL(filterSelected(const QString&)), this, + SLOT(updateAutomaticFileExtension())); +} + +Qt5FilePicker::~Qt5FilePicker() +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this]() { + // must delete it in main thread, otherwise + // QSocketNotifier::setEnabled() will crash us + m_pFileDialog.reset(); + }); +} + +void SAL_CALL +Qt5FilePicker::addFilePickerListener(const uno::Reference& xListener) +{ + SolarMutexGuard aGuard; + m_xListener = xListener; +} + +void SAL_CALL Qt5FilePicker::removeFilePickerListener(const uno::Reference&) +{ + SolarMutexGuard aGuard; + m_xListener.clear(); +} + +void SAL_CALL Qt5FilePicker::setTitle(const OUString& title) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread( + [this, &title]() { m_pFileDialog->setWindowTitle(toQString(title)); }); +} + +sal_Int16 SAL_CALL Qt5FilePicker::execute() +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + sal_uInt16 ret; + pSalInst->RunInMainThread([&ret, this]() { ret = execute(); }); + return ret; + } + + QWidget* pTransientParent = m_pParentWidget; + if (!pTransientParent) + { + vcl::Window* pWindow = ::Application::GetActiveTopWindow(); + if (pWindow) + { + Qt5Frame* pFrame = dynamic_cast(pWindow->ImplGetFrame()); + assert(pFrame); + if (pFrame) + pTransientParent = pFrame->asChild(); + } + } + + if (!m_aNamedFilterList.isEmpty()) + m_pFileDialog->setNameFilters(m_aNamedFilterList); + if (!m_aCurrentFilter.isEmpty()) + m_pFileDialog->selectNameFilter(m_aCurrentFilter); + + updateAutomaticFileExtension(); + + uno::Reference xDesktop(css::frame::Desktop::create(m_context), + UNO_QUERY_THROW); + + // will hide the window, so do before show + m_pFileDialog->setParent(pTransientParent, m_pFileDialog->windowFlags()); + m_pFileDialog->show(); + xDesktop->addTerminateListener(this); + int result = m_pFileDialog->exec(); + xDesktop->removeTerminateListener(this); + m_pFileDialog->setParent(nullptr, m_pFileDialog->windowFlags()); + + if (QFileDialog::Rejected == result) + return ExecutableDialogResults::CANCEL; + return ExecutableDialogResults::OK; +} + +void SAL_CALL Qt5FilePicker::setMultiSelectionMode(sal_Bool multiSelect) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, multiSelect]() { + if (m_bIsFolderPicker || m_pFileDialog->acceptMode() == QFileDialog::AcceptSave) + return; + + m_pFileDialog->setFileMode(multiSelect ? QFileDialog::ExistingFiles + : QFileDialog::ExistingFile); + }); +} + +void SAL_CALL Qt5FilePicker::setDefaultName(const OUString& name) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &name]() { m_pFileDialog->selectFile(toQString(name)); }); +} + +void SAL_CALL Qt5FilePicker::setDisplayDirectory(const OUString& dir) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &dir]() { + QString qDir(toQString(dir)); + m_pFileDialog->setDirectoryUrl(QUrl(qDir)); + }); +} + +OUString SAL_CALL Qt5FilePicker::getDisplayDirectory() +{ + SolarMutexGuard g; + OUString ret; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread( + [&ret, this]() { ret = toOUString(m_pFileDialog->directoryUrl().toString()); }); + return ret; +} + +uno::Sequence SAL_CALL Qt5FilePicker::getFiles() +{ + uno::Sequence seq = getSelectedFiles(); + if (seq.getLength() > 1) + seq.realloc(1); + return seq; +} + +uno::Sequence SAL_CALL Qt5FilePicker::getSelectedFiles() +{ + SolarMutexGuard g; + QList urls; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([&urls, this]() { urls = m_pFileDialog->selectedUrls(); }); + + uno::Sequence seq(urls.size()); + + auto const trans = css::uri::ExternalUriReferenceTranslator::create(m_context); + size_t i = 0; + for (const QUrl& aURL : urls) + { + // Unlike LO, QFileDialog () apparently always + // treats file-system pathnames as UTF-8--encoded, regardless of LANG/LC_CTYPE locale + // setting. And pathnames containing byte sequences that are not valid UTF-8 are apparently + // filtered out and not even displayed by QFileDialog, so aURL will always have a "payload" + // that matches the pathname's byte sequence. So the pathname's byte sequence (which + // happens to also be aURL's payload) in the LANG/LC_CTYPE encoding needs to be converted + // into LO's internal UTF-8 file URL encoding via + // XExternalUriReferenceTranslator::translateToInternal (which looks somewhat paradoxical as + // aURL.toEncoded() nominally already has a UTF-8 payload): + auto const extUrl = toOUString(aURL.toEncoded()); + auto intUrl = trans->translateToInternal(extUrl); + if (intUrl.isEmpty()) + { + // If translation failed, fall back to original URL: + SAL_WARN("vcl.qt5", "cannot convert <" << extUrl << "> from locale encoding to UTF-8"); + intUrl = extUrl; + } + seq[i++] = intUrl; + } + + return seq; +} + +void SAL_CALL Qt5FilePicker::appendFilter(const OUString& title, const OUString& filter) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, &title, &filter]() { appendFilter(title, filter); }); + return; + } + + // '/' need to be escaped else they are assumed to be mime types + QString sTitle = toQString(title).replace("/", "\\/"); + + QString sFilterName = sTitle; + // the Qt5 non-native file picker adds the extensions to the filter title, so strip them + if (m_pFileDialog->testOption(QFileDialog::DontUseNativeDialog)) + { + int pos = sFilterName.indexOf(" ("); + if (pos >= 0) + sFilterName.truncate(pos); + } + + QString sGlobFilter = toQString(filter); + + // LibreOffice gives us filters separated by ';' qt dialogs just want space separated + sGlobFilter.replace(";", " "); + + // make sure "*.*" is not used as "all files" + sGlobFilter.replace("*.*", "*"); + + m_aNamedFilterList << QStringLiteral("%1 (%2)").arg(sFilterName, sGlobFilter); + m_aTitleToFilterMap[sTitle] = m_aNamedFilterList.constLast(); + m_aNamedFilterToExtensionMap[m_aNamedFilterList.constLast()] = sGlobFilter; +} + +void SAL_CALL Qt5FilePicker::setCurrentFilter(const OUString& title) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, &title]() { + m_aCurrentFilter = m_aTitleToFilterMap.value(toQString(title).replace("/", "\\/")); + }); +} + +OUString SAL_CALL Qt5FilePicker::getCurrentFilter() +{ + SolarMutexGuard g; + QString filter; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([&filter, this]() { + filter = m_aTitleToFilterMap.key(m_pFileDialog->selectedNameFilter()); + }); + + if (filter.isEmpty()) + filter = "ODF Text Document (.odt)"; + return toOUString(filter); +} + +void SAL_CALL Qt5FilePicker::appendFilterGroup(const OUString& rGroupTitle, + const uno::Sequence& filters) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread( + [this, &rGroupTitle, &filters]() { appendFilterGroup(rGroupTitle, filters); }); + return; + } + + const sal_uInt16 length = filters.getLength(); + for (sal_uInt16 i = 0; i < length; ++i) + { + beans::StringPair aPair = filters[i]; + appendFilter(aPair.First, aPair.Second); + } +} + +uno::Any Qt5FilePicker::handleGetListValue(const QComboBox* pWidget, sal_Int16 nControlAction) +{ + uno::Any aAny; + switch (nControlAction) + { + case ControlActions::GET_ITEMS: + { + Sequence aItemList(pWidget->count()); + for (sal_Int32 i = 0; i < pWidget->count(); ++i) + aItemList[i] = toOUString(pWidget->itemText(i)); + aAny <<= aItemList; + break; + } + case ControlActions::GET_SELECTED_ITEM: + { + if (!pWidget->currentText().isEmpty()) + aAny <<= toOUString(pWidget->currentText()); + break; + } + case ControlActions::GET_SELECTED_ITEM_INDEX: + { + if (pWidget->currentIndex() >= 0) + aAny <<= static_cast(pWidget->currentIndex()); + break; + } + default: + SAL_WARN("vcl.qt5", + "undocumented/unimplemented ControlAction for a list " << nControlAction); + break; + } + return aAny; +} + +void Qt5FilePicker::handleSetListValue(QComboBox* pWidget, sal_Int16 nControlAction, + const uno::Any& rValue) +{ + switch (nControlAction) + { + case ControlActions::ADD_ITEM: + { + OUString sItem; + rValue >>= sItem; + pWidget->addItem(toQString(sItem)); + break; + } + case ControlActions::ADD_ITEMS: + { + Sequence aStringList; + rValue >>= aStringList; + for (auto const& sItem : std::as_const(aStringList)) + pWidget->addItem(toQString(sItem)); + break; + } + case ControlActions::DELETE_ITEM: + { + sal_Int32 nPos = 0; + rValue >>= nPos; + pWidget->removeItem(nPos); + break; + } + case ControlActions::DELETE_ITEMS: + { + pWidget->clear(); + break; + } + case ControlActions::SET_SELECT_ITEM: + { + sal_Int32 nPos = 0; + rValue >>= nPos; + pWidget->setCurrentIndex(nPos); + break; + } + default: + SAL_WARN("vcl.qt5", + "undocumented/unimplemented ControlAction for a list " << nControlAction); + break; + } + + pWidget->setEnabled(pWidget->count() > 0); +} + +void SAL_CALL Qt5FilePicker::setValue(sal_Int16 controlId, sal_Int16 nControlAction, + const uno::Any& value) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, controlId, nControlAction, &value]() { + setValue(controlId, nControlAction, value); + }); + return; + } + + if (m_aCustomWidgetsMap.contains(controlId)) + { + QWidget* widget = m_aCustomWidgetsMap.value(controlId); + QCheckBox* cb = dynamic_cast(widget); + if (cb) + cb->setChecked(value.get()); + else + { + QComboBox* combo = dynamic_cast(widget); + if (combo) + handleSetListValue(combo, nControlAction, value); + } + } + else + SAL_WARN("vcl.qt5", "set value on unknown control " << controlId); +} + +uno::Any SAL_CALL Qt5FilePicker::getValue(sal_Int16 controlId, sal_Int16 nControlAction) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + uno::Any ret; + pSalInst->RunInMainThread([&ret, this, controlId, nControlAction]() { + ret = getValue(controlId, nControlAction); + }); + return ret; + } + + uno::Any res(false); + if (m_aCustomWidgetsMap.contains(controlId)) + { + QWidget* widget = m_aCustomWidgetsMap.value(controlId); + QCheckBox* cb = dynamic_cast(widget); + if (cb) + res <<= cb->isChecked(); + else + { + QComboBox* combo = dynamic_cast(widget); + if (combo) + res = handleGetListValue(combo, nControlAction); + } + } + else + SAL_WARN("vcl.qt5", "get value on unknown control " << controlId); + + return res; +} + +void SAL_CALL Qt5FilePicker::enableControl(sal_Int16 controlId, sal_Bool enable) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, controlId, enable]() { + if (m_aCustomWidgetsMap.contains(controlId)) + m_aCustomWidgetsMap.value(controlId)->setEnabled(enable); + else + SAL_WARN("vcl.qt5", "enable unknown control " << controlId); + }); +} + +void SAL_CALL Qt5FilePicker::setLabel(sal_Int16 controlId, const OUString& label) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, controlId, label]() { setLabel(controlId, label); }); + return; + } + + if (m_aCustomWidgetsMap.contains(controlId)) + { + QCheckBox* cb = dynamic_cast(m_aCustomWidgetsMap.value(controlId)); + if (cb) + cb->setText(toQString(label)); + } + else + SAL_WARN("vcl.qt5", "set label on unknown control " << controlId); +} + +OUString SAL_CALL Qt5FilePicker::getLabel(sal_Int16 controlId) +{ + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + OUString ret; + pSalInst->RunInMainThread([&ret, this, controlId]() { ret = getLabel(controlId); }); + return ret; + } + + QString label; + if (m_aCustomWidgetsMap.contains(controlId)) + { + QCheckBox* cb = dynamic_cast(m_aCustomWidgetsMap.value(controlId)); + if (cb) + label = cb->text(); + } + else + SAL_WARN("vcl.qt5", "get label on unknown control " << controlId); + + return toOUString(label); +} + +QString Qt5FilePicker::getResString(const char* pResId) +{ + QString aResString; + + if (pResId == nullptr) + return aResString; + + aResString = toQString(VclResId(pResId)); + + return aResString.replace('~', '&'); +} + +void Qt5FilePicker::addCustomControl(sal_Int16 controlId) +{ + QWidget* widget = nullptr; + QLabel* label = nullptr; + const char* resId = nullptr; + QCheckBox* pCheckbox = nullptr; + + switch (controlId) + { + case CHECKBOX_AUTOEXTENSION: + resId = STR_FPICKER_AUTO_EXTENSION; + break; + case CHECKBOX_PASSWORD: + resId = STR_FPICKER_PASSWORD; + break; + case CHECKBOX_FILTEROPTIONS: + resId = STR_FPICKER_FILTER_OPTIONS; + break; + case CHECKBOX_READONLY: + resId = STR_FPICKER_READONLY; + break; + case CHECKBOX_LINK: + resId = STR_FPICKER_INSERT_AS_LINK; + break; + case CHECKBOX_PREVIEW: + resId = STR_FPICKER_SHOW_PREVIEW; + break; + case CHECKBOX_SELECTION: + resId = STR_FPICKER_SELECTION; + break; + case CHECKBOX_GPGENCRYPTION: + resId = STR_FPICKER_GPGENCRYPT; + break; + case PUSHBUTTON_PLAY: + resId = STR_FPICKER_PLAY; + break; + case LISTBOX_VERSION: + resId = STR_FPICKER_VERSION; + break; + case LISTBOX_TEMPLATE: + resId = STR_FPICKER_TEMPLATES; + break; + case LISTBOX_IMAGE_TEMPLATE: + resId = STR_FPICKER_IMAGE_TEMPLATE; + break; + case LISTBOX_IMAGE_ANCHOR: + resId = STR_FPICKER_IMAGE_ANCHOR; + break; + case LISTBOX_VERSION_LABEL: + case LISTBOX_TEMPLATE_LABEL: + case LISTBOX_IMAGE_TEMPLATE_LABEL: + case LISTBOX_IMAGE_ANCHOR_LABEL: + case LISTBOX_FILTER_SELECTOR: + break; + } + + switch (controlId) + { + case CHECKBOX_AUTOEXTENSION: + pCheckbox = new QCheckBox(getResString(resId), m_pExtraControls); + // to add/remove automatic file extension based on checkbox + connect(pCheckbox, SIGNAL(stateChanged(int)), this, + SLOT(updateAutomaticFileExtension())); + widget = pCheckbox; + break; + case CHECKBOX_PASSWORD: + case CHECKBOX_FILTEROPTIONS: + case CHECKBOX_READONLY: + case CHECKBOX_LINK: + case CHECKBOX_PREVIEW: + case CHECKBOX_SELECTION: + case CHECKBOX_GPGENCRYPTION: + widget = new QCheckBox(getResString(resId), m_pExtraControls); + break; + case PUSHBUTTON_PLAY: + break; + case LISTBOX_VERSION: + case LISTBOX_TEMPLATE: + case LISTBOX_IMAGE_ANCHOR: + case LISTBOX_IMAGE_TEMPLATE: + case LISTBOX_FILTER_SELECTOR: + label = new QLabel(getResString(resId), m_pExtraControls); + widget = new QComboBox(m_pExtraControls); + label->setBuddy(widget); + break; + case LISTBOX_VERSION_LABEL: + case LISTBOX_TEMPLATE_LABEL: + case LISTBOX_IMAGE_TEMPLATE_LABEL: + case LISTBOX_IMAGE_ANCHOR_LABEL: + break; + } + + if (widget) + { + const int row = m_pLayout->rowCount(); + if (label) + m_pLayout->addWidget(label, row, 0); + m_pLayout->addWidget(widget, row, 1); + m_aCustomWidgetsMap.insert(controlId, widget); + } +} + +void SAL_CALL Qt5FilePicker::initialize(const uno::Sequence& args) +{ + // parameter checking + uno::Any arg; + if (args.getLength() == 0) + throw lang::IllegalArgumentException("no arguments", static_cast(this), 1); + + arg = args[0]; + + if ((arg.getValueType() != cppu::UnoType::get()) + && (arg.getValueType() != cppu::UnoType::get())) + { + throw lang::IllegalArgumentException("invalid argument type", + static_cast(this), 1); + } + + SolarMutexGuard g; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, args]() { initialize(args); }); + return; + } + + m_aNamedFilterToExtensionMap.clear(); + m_aNamedFilterList.clear(); + m_aTitleToFilterMap.clear(); + m_aCurrentFilter.clear(); + + sal_Int16 templateId = -1; + arg >>= templateId; + + QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen; + switch (templateId) + { + case FILEOPEN_SIMPLE: + break; + + case FILESAVE_SIMPLE: + acceptMode = QFileDialog::AcceptSave; + break; + + case FILESAVE_AUTOEXTENSION: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + break; + + case FILESAVE_AUTOEXTENSION_PASSWORD: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_PASSWORD); + addCustomControl(CHECKBOX_GPGENCRYPTION); + break; + + case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_PASSWORD); + addCustomControl(CHECKBOX_GPGENCRYPTION); + addCustomControl(CHECKBOX_FILTEROPTIONS); + break; + + case FILESAVE_AUTOEXTENSION_SELECTION: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(CHECKBOX_SELECTION); + break; + + case FILESAVE_AUTOEXTENSION_TEMPLATE: + acceptMode = QFileDialog::AcceptSave; + addCustomControl(CHECKBOX_AUTOEXTENSION); + addCustomControl(LISTBOX_TEMPLATE); + break; + + case FILEOPEN_LINK_PREVIEW_IMAGE_TEMPLATE: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + addCustomControl(LISTBOX_IMAGE_TEMPLATE); + break; + + case FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + addCustomControl(LISTBOX_IMAGE_ANCHOR); + break; + + case FILEOPEN_PLAY: + addCustomControl(PUSHBUTTON_PLAY); + break; + + case FILEOPEN_LINK_PLAY: + addCustomControl(CHECKBOX_LINK); + addCustomControl(PUSHBUTTON_PLAY); + break; + + case FILEOPEN_READONLY_VERSION: + addCustomControl(CHECKBOX_READONLY); + addCustomControl(LISTBOX_VERSION); + break; + + case FILEOPEN_LINK_PREVIEW: + addCustomControl(CHECKBOX_LINK); + addCustomControl(CHECKBOX_PREVIEW); + break; + + case FILEOPEN_PREVIEW: + addCustomControl(CHECKBOX_PREVIEW); + break; + + default: + throw lang::IllegalArgumentException("Unknown template", + static_cast(this), 1); + } + + const char* resId = nullptr; + switch (acceptMode) + { + case QFileDialog::AcceptOpen: + resId = STR_FPICKER_OPEN; + break; + case QFileDialog::AcceptSave: + resId = STR_FPICKER_SAVE; + m_pFileDialog->setFileMode(QFileDialog::AnyFile); + break; + } + + m_pFileDialog->setAcceptMode(acceptMode); + m_pFileDialog->setWindowTitle(getResString(resId)); + + css::uno::Reference xParentWindow; + if (args.getLength() > 1) + args[1] >>= xParentWindow; + if (xParentWindow.is()) + { + css::uno::Reference xSysWinPeer(xParentWindow, + css::uno::UNO_QUERY); + if (xSysWinPeer.is()) + { + // the sal_*Int8 handling is strange, but it's public API - no way around + css::uno::Sequence aProcessIdent(16); + rtl_getGlobalProcessId(reinterpret_cast(aProcessIdent.getArray())); + uno::Any aAny = xSysWinPeer->getWindowHandle( + aProcessIdent, css::lang::SystemDependent::SYSTEM_XWINDOW); + css::awt::SystemDependentXWindow xSysWin; + aAny >>= xSysWin; + + const auto& pFrames = pSalInst->getFrames(); + const long aWindowHandle = xSysWin.WindowHandle; + const auto it = std::find_if(pFrames.begin(), pFrames.end(), + [&aWindowHandle](auto pFrame) -> bool { + const SystemEnvData* pData = pFrame->GetSystemData(); + return pData && long(pData->aWindow) == aWindowHandle; + }); + if (it != pFrames.end()) + m_pParentWidget = static_cast(*it)->asChild(); + } + } +} + +void SAL_CALL Qt5FilePicker::cancel() { m_pFileDialog->reject(); } + +void SAL_CALL Qt5FilePicker::disposing(const lang::EventObject& rEvent) +{ + uno::Reference xFilePickerListener(rEvent.Source, uno::UNO_QUERY); + + if (xFilePickerListener.is()) + { + removeFilePickerListener(xFilePickerListener); + } +} + +void SAL_CALL Qt5FilePicker::queryTermination(const css::lang::EventObject&) +{ + throw css::frame::TerminationVetoException(); +} + +void SAL_CALL Qt5FilePicker::notifyTermination(const css::lang::EventObject&) +{ + SolarMutexGuard aGuard; + m_pFileDialog->reject(); +} + +OUString SAL_CALL Qt5FilePicker::getImplementationName() +{ + return "com.sun.star.ui.dialogs.Qt5FilePicker"; +} + +sal_Bool SAL_CALL Qt5FilePicker::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +uno::Sequence SAL_CALL Qt5FilePicker::getSupportedServiceNames() +{ + return FilePicker_getSupportedServiceNames(); +} + +void Qt5FilePicker::updateAutomaticFileExtension() +{ + bool bSetAutoExtension + = getValue(CHECKBOX_AUTOEXTENSION, ControlActions::GET_SELECTED_ITEM).get(); + if (bSetAutoExtension) + { + QString sSuffix = m_aNamedFilterToExtensionMap.value(m_pFileDialog->selectedNameFilter()); + // string is "*." if a specific filter was selected that has exactly one possible file extension + if (sSuffix.lastIndexOf("*.") == 0) + { + sSuffix = sSuffix.remove("*."); + m_pFileDialog->setDefaultSuffix(sSuffix); + } + else + { + // fall back to setting none otherwise + SAL_INFO( + "vcl.qt5", + "Unable to retrieve unambiguous file extension. Will not add any automatically."); + bSetAutoExtension = false; + } + } + + if (!bSetAutoExtension) + m_pFileDialog->setDefaultSuffix(""); +} + +void Qt5FilePicker::filterSelected(const QString&) +{ + FilePickerEvent aEvent; + aEvent.ElementId = LISTBOX_FILTER; + SAL_INFO("vcl.qt5", "filter changed"); + if (m_xListener.is()) + m_xListener->controlStateChanged(aEvent); +} + +void Qt5FilePicker::currentChanged(const QString&) +{ + FilePickerEvent aEvent; + SAL_INFO("vcl.qt5", "file selection changed"); + if (m_xListener.is()) + m_xListener->fileSelectionChanged(aEvent); +} + +OUString Qt5FilePicker::getDirectory() +{ + uno::Sequence seq = getSelectedFiles(); + if (seq.getLength() > 1) + seq.realloc(1); + return seq[0]; +} + +void Qt5FilePicker::setDescription(const OUString&) {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Font.cxx b/vcl/qt5/Qt5Font.cxx new file mode 100644 index 000000000..2ab614043 --- /dev/null +++ b/vcl/qt5/Qt5Font.cxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +static inline void applyWeight(Qt5Font& rFont, FontWeight eWeight) +{ + switch (eWeight) + { + case WEIGHT_THIN: + rFont.setWeight(QFont::Thin); + break; + case WEIGHT_ULTRALIGHT: + rFont.setWeight(QFont::ExtraLight); + break; + case WEIGHT_LIGHT: + rFont.setWeight(QFont::Light); + break; + case WEIGHT_SEMILIGHT: + [[fallthrough]]; + case WEIGHT_NORMAL: + rFont.setWeight(QFont::Normal); + break; + case WEIGHT_MEDIUM: + rFont.setWeight(QFont::Medium); + break; + case WEIGHT_SEMIBOLD: + rFont.setWeight(QFont::DemiBold); + break; + case WEIGHT_BOLD: + rFont.setWeight(QFont::Bold); + break; + case WEIGHT_ULTRABOLD: + rFont.setWeight(QFont::ExtraBold); + break; + case WEIGHT_BLACK: + rFont.setWeight(QFont::Black); + break; + default: + break; + } +} + +static inline void applyStretch(Qt5Font& rFont, FontWidth eWidthType) +{ + switch (eWidthType) + { + case WIDTH_DONTKNOW: + rFont.setStretch(QFont::AnyStretch); + break; + case WIDTH_ULTRA_CONDENSED: + rFont.setStretch(QFont::UltraCondensed); + break; + case WIDTH_EXTRA_CONDENSED: + rFont.setStretch(QFont::ExtraCondensed); + break; + case WIDTH_CONDENSED: + rFont.setStretch(QFont::Condensed); + break; + case WIDTH_SEMI_CONDENSED: + rFont.setStretch(QFont::SemiCondensed); + break; + case WIDTH_NORMAL: + rFont.setStretch(QFont::Unstretched); + break; + case WIDTH_SEMI_EXPANDED: + rFont.setStretch(QFont::SemiExpanded); + break; + case WIDTH_EXPANDED: + rFont.setStretch(QFont::Expanded); + break; + case WIDTH_EXTRA_EXPANDED: + rFont.setStretch(QFont::ExtraExpanded); + break; + case WIDTH_ULTRA_EXPANDED: + rFont.setStretch(QFont::UltraExpanded); + break; + default: + break; + } +} + +static inline void applyStyle(Qt5Font& rFont, FontItalic eItalic) +{ + switch (eItalic) + { + case ITALIC_NONE: + rFont.setStyle(QFont::Style::StyleNormal); + break; + case ITALIC_OBLIQUE: + rFont.setStyle(QFont::Style::StyleOblique); + break; + case ITALIC_NORMAL: + rFont.setStyle(QFont::Style::StyleItalic); + break; + default: + break; + } +} + +Qt5Font::Qt5Font(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP) + : LogicalFontInstance(rPFF, rFSP) +{ + setFamily(toQString(rPFF.GetFamilyName())); + applyWeight(*this, rPFF.GetWeight()); + setPixelSize(rFSP.mnHeight); + applyStretch(*this, rPFF.GetWidthType()); + applyStyle(*this, rFSP.GetItalic()); +} + +static hb_blob_t* getFontTable(hb_face_t*, hb_tag_t nTableTag, void* pUserData) +{ + char pTagName[5]; + LogicalFontInstance::DecodeOpenTypeTag(nTableTag, pTagName); + + Qt5Font* pFont = static_cast(pUserData); + QRawFont aRawFont(QRawFont::fromFont(*pFont)); + QByteArray aTable = aRawFont.fontTable(pTagName); + const sal_uInt32 nLength = aTable.size(); + + hb_blob_t* pBlob = nullptr; + if (nLength > 0) + pBlob = hb_blob_create(aTable.data(), nLength, HB_MEMORY_MODE_DUPLICATE, nullptr, nullptr); + return pBlob; +} + +hb_font_t* Qt5Font::ImplInitHbFont() +{ + return InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr)); +} + +bool Qt5Font::GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const { return false; } + +bool Qt5Font::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool) const +{ + QRawFont aRawFont(QRawFont::fromFont(*this)); + rRect = toRectangle(aRawFont.boundingRect(nId).toAlignedRect()); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5FontFace.cxx b/vcl/qt5/Qt5FontFace.cxx new file mode 100644 index 000000000..8ac2f87d1 --- /dev/null +++ b/vcl/qt5/Qt5FontFace.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace vcl; + +Qt5FontFace::Qt5FontFace(const Qt5FontFace& rSrc) + : PhysicalFontFace(rSrc) + , m_aFontId(rSrc.m_aFontId) +{ + if (rSrc.m_xCharMap.is()) + m_xCharMap = rSrc.m_xCharMap; +} + +FontWeight Qt5FontFace::toFontWeight(const int nWeight) +{ + if (nWeight <= QFont::Thin) + return WEIGHT_THIN; + if (nWeight <= QFont::ExtraLight) + return WEIGHT_ULTRALIGHT; + if (nWeight <= QFont::Light) + return WEIGHT_LIGHT; + if (nWeight <= QFont::Normal) + return WEIGHT_NORMAL; + if (nWeight <= QFont::Medium) + return WEIGHT_MEDIUM; + if (nWeight <= QFont::DemiBold) + return WEIGHT_SEMIBOLD; + if (nWeight <= QFont::Bold) + return WEIGHT_BOLD; + if (nWeight <= QFont::ExtraBold) + return WEIGHT_ULTRABOLD; + return WEIGHT_BLACK; +} + +FontWidth Qt5FontFace::toFontWidth(const int nStretch) +{ + if (nStretch == 0) // QFont::AnyStretch since Qt 5.8 + return WIDTH_DONTKNOW; + if (nStretch <= QFont::UltraCondensed) + return WIDTH_ULTRA_CONDENSED; + if (nStretch <= QFont::ExtraCondensed) + return WIDTH_EXTRA_CONDENSED; + if (nStretch <= QFont::Condensed) + return WIDTH_CONDENSED; + if (nStretch <= QFont::SemiCondensed) + return WIDTH_SEMI_CONDENSED; + if (nStretch <= QFont::Unstretched) + return WIDTH_NORMAL; + if (nStretch <= QFont::SemiExpanded) + return WIDTH_SEMI_EXPANDED; + if (nStretch <= QFont::Expanded) + return WIDTH_EXPANDED; + if (nStretch <= QFont::ExtraExpanded) + return WIDTH_EXTRA_EXPANDED; + return WIDTH_ULTRA_EXPANDED; +} + +FontItalic Qt5FontFace::toFontItalic(const QFont::Style eStyle) +{ + switch (eStyle) + { + case QFont::StyleNormal: + return ITALIC_NONE; + case QFont::StyleItalic: + return ITALIC_NORMAL; + case QFont::StyleOblique: + return ITALIC_OBLIQUE; + } + + return ITALIC_NONE; +} + +void Qt5FontFace::fillAttributesFromQFont(const QFont& rFont, FontAttributes& rFA) +{ + QFontInfo aFontInfo(rFont); + + rFA.SetFamilyName(toOUString(aFontInfo.family())); + if (IsStarSymbol(toOUString(aFontInfo.family()))) + rFA.SetSymbolFlag(true); + rFA.SetStyleName(toOUString(aFontInfo.styleName())); + rFA.SetPitch(aFontInfo.fixedPitch() ? PITCH_FIXED : PITCH_VARIABLE); + rFA.SetWeight(Qt5FontFace::toFontWeight(aFontInfo.weight())); + rFA.SetItalic(Qt5FontFace::toFontItalic(aFontInfo.style())); + rFA.SetWidthType(Qt5FontFace::toFontWidth(rFont.stretch())); +} + +Qt5FontFace* Qt5FontFace::fromQFont(const QFont& rFont) +{ + FontAttributes aFA; + fillAttributesFromQFont(rFont, aFA); + return new Qt5FontFace(aFA, rFont.toString()); +} + +Qt5FontFace* Qt5FontFace::fromQFontDatabase(const QString& aFamily, const QString& aStyle) +{ + QFontDatabase aFDB; + FontAttributes aFA; + aFA.SetFamilyName(toOUString(aFamily)); + if (IsStarSymbol(aFA.GetFamilyName())) + aFA.SetSymbolFlag(true); + aFA.SetStyleName(toOUString(aStyle)); + aFA.SetPitch(aFDB.isFixedPitch(aFamily, aStyle) ? PITCH_FIXED : PITCH_VARIABLE); + aFA.SetWeight(Qt5FontFace::toFontWeight(aFDB.weight(aFamily, aStyle))); + aFA.SetItalic(aFDB.italic(aFamily, aStyle) ? ITALIC_NORMAL : ITALIC_NONE); + return new Qt5FontFace(aFA, aFamily + "," + aStyle); +} + +Qt5FontFace::Qt5FontFace(const FontAttributes& rFA, const QString& rFontID) + : PhysicalFontFace(rFA) + , m_aFontId(rFontID) + , m_bFontCapabilitiesRead(false) +{ +} + +sal_IntPtr Qt5FontFace::GetFontId() const { return reinterpret_cast(&m_aFontId); } + +rtl::Reference +Qt5FontFace::CreateFontInstance(const FontSelectPattern& rFSD) const +{ + return new Qt5Font(*this, rFSD); +} + +const FontCharMapRef& Qt5FontFace::GetFontCharMap() const +{ + if (m_xCharMap.is()) + return m_xCharMap; + + QFont aFont; + aFont.fromString(m_aFontId); + QRawFont aRawFont(QRawFont::fromFont(aFont)); + QByteArray aCMapTable = aRawFont.fontTable("cmap"); + if (aCMapTable.isEmpty()) + { + m_xCharMap = new FontCharMap(); + return m_xCharMap; + } + + CmapResult aCmapResult; + if (ParseCMAP(reinterpret_cast(aCMapTable.data()), aCMapTable.size(), + aCmapResult)) + m_xCharMap = new FontCharMap(aCmapResult); + + return m_xCharMap; +} + +bool Qt5FontFace::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const +{ + // read this only once per font + if (m_bFontCapabilitiesRead) + { + rFontCapabilities = m_aFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; + } + m_bFontCapabilitiesRead = true; + + QFont aFont; + aFont.fromString(m_aFontId); + QRawFont aRawFont(QRawFont::fromFont(aFont)); + QByteArray aOS2Table = aRawFont.fontTable("OS/2"); + if (!aOS2Table.isEmpty()) + { + vcl::getTTCoverage(m_aFontCapabilities.oUnicodeRange, m_aFontCapabilities.oCodePageRange, + reinterpret_cast(aOS2Table.data()), + aOS2Table.size()); + } + + rFontCapabilities = m_aFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Frame.cxx b/vcl/qt5/Qt5Frame.cxx new file mode 100644 index 000000000..936216b9d --- /dev/null +++ b/vcl/qt5/Qt5Frame.cxx @@ -0,0 +1,1449 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if QT5_USING_X11 +#include +#include +#if QT5_HAVE_XCB_ICCCM +#include +#endif +#endif + +#include +#include +#include +#include + +#include + +#include +#include + +#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM +static bool g_bNeedsWmHintsWindowGroup = true; +static xcb_atom_t g_aXcbClientLeaderAtom = 0; +#endif + +static void SvpDamageHandler(void* handle, sal_Int32 nExtentsX, sal_Int32 nExtentsY, + sal_Int32 nExtentsWidth, sal_Int32 nExtentsHeight) +{ + Qt5Frame* pThis = static_cast(handle); + pThis->Damage(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight); +} + +namespace +{ +sal_Int32 screenNumber(const QScreen* pScreen) +{ + const QList screens = QApplication::screens(); + + sal_Int32 nScreen = 0; + bool bFound = false; + for (const QScreen* pCurScreen : screens) + { + if (pScreen == pCurScreen) + { + bFound = true; + break; + } + nScreen++; + } + + return bFound ? nScreen : -1; +} +} + +Qt5Frame::Qt5Frame(Qt5Frame* pParent, SalFrameStyleFlags nStyle, bool bUseCairo) + : m_pTopLevel(nullptr) + , m_bUseCairo(bUseCairo) + , m_pSvpGraphics(nullptr) + , m_bNullRegion(true) + , m_bGraphicsInUse(false) + , m_bGraphicsInvalid(false) + , m_ePointerStyle(PointerStyle::Arrow) + , m_pDragSource(nullptr) + , m_pDropTarget(nullptr) + , m_bInDrag(false) + , m_bDefaultSize(true) + , m_bDefaultPos(true) + , m_bFullScreen(false) + , m_bFullScreenSpanAll(false) +{ + Qt5Instance* pInst = static_cast(GetSalData()->m_pInstance); + pInst->insertFrame(this); + + m_aDamageHandler.handle = this; + m_aDamageHandler.damaged = ::SvpDamageHandler; + + if (nStyle & SalFrameStyleFlags::DEFAULT) // ensure default style + { + nStyle |= SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE + | SalFrameStyleFlags::CLOSEABLE; + nStyle &= ~SalFrameStyleFlags::FLOAT; + } + + m_nStyle = nStyle; + m_pParent = pParent; + + Qt::WindowFlags aWinFlags; + if (!(nStyle & SalFrameStyleFlags::SYSTEMCHILD)) + { + if (nStyle & SalFrameStyleFlags::INTRO) + aWinFlags |= Qt::SplashScreen; + // floating toolbars are frameless tool windows + // + they must be able to receive keyboard focus + else if ((nStyle & SalFrameStyleFlags::FLOAT) + && (nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)) + aWinFlags |= Qt::Tool | Qt::FramelessWindowHint; + else if (nStyle & (SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::TOOLTIP)) + aWinFlags |= Qt::ToolTip; + else if ((nStyle & SalFrameStyleFlags::FLOAT) + && !(nStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)) + aWinFlags |= Qt::Popup; + else if (nStyle & SalFrameStyleFlags::TOOLWINDOW) + aWinFlags |= Qt::Tool; + // top level windows can't be transient in Qt, so make them dialogs, if they have a parent. At least + // the plasma shell relies on this setting to skip dialogs in the window list. And Qt Xcb will just + // set transient for the types Dialog, Sheet, Tool, SplashScreen, ToolTip, Drawer and Popup. + else if (nStyle & SalFrameStyleFlags::DIALOG || m_pParent) + aWinFlags |= Qt::Dialog; + else + aWinFlags |= Qt::Window; + } + + if (aWinFlags == Qt::Window) + { + m_pTopLevel = new Qt5MainWindow(*this, aWinFlags); + m_pQWidget = new Qt5Widget(*this, aWinFlags); + m_pTopLevel->setCentralWidget(m_pQWidget); + m_pTopLevel->setFocusProxy(m_pQWidget); + } + else + m_pQWidget = new Qt5Widget(*this, aWinFlags); + + if (pParent && !(pParent->m_nStyle & SalFrameStyleFlags::PLUG)) + { + QWindow* pParentWindow = pParent->GetQWidget()->window()->windowHandle(); + QWindow* pChildWindow = asChild()->window()->windowHandle(); + if (pParentWindow && pChildWindow && (pParentWindow != pChildWindow)) + pChildWindow->setTransientParent(pParentWindow); + } + + // Calling 'QWidget::winId()' implicitly enables native windows to be used + // rather than "alien widgets" that are unknown to the windowing system, + // s. https://doc.qt.io/qt-5/qwidget.html#native-widgets-vs-alien-widgets + // Avoid this on Wayland due to problems with missing 'mouseMoveEvent's, + // s. tdf#122293/QTBUG-75766 + const bool bWayland = QGuiApplication::platformName() == "wayland"; + if (!bWayland) + m_aSystemData.aWindow = m_pQWidget->winId(); + else + { + // TODO implement as needed for Wayland, + // s.a. commit c0d4f3ad3307c which did this for gtk3 + // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); + // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); + // m_aSystemData.aWindow = reinterpret_cast( + // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); + } + + m_aSystemData.aShellWindow = reinterpret_cast(this); + //m_aSystemData.pSalFrame = this; + m_aSystemData.pWidget = m_pQWidget; + //m_aSystemData.nScreen = m_nXScreen.getXScreen(); + m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; + if (!bWayland) + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + else + m_aSystemData.platform = SystemEnvData::Platform::Wayland; + + SetIcon(SV_ICON_ID_OFFICE); + + fixICCCMwindowGroup(); +} + +void Qt5Frame::fixICCCMwindowGroup() +{ +#if QT5_USING_X11 && QT5_HAVE_XCB_ICCCM + // older Qt5 just sets WM_CLIENT_LEADER, but not the XCB_ICCCM_WM_HINT_WINDOW_GROUP + // see Qt commit 0de4b326d8 ("xcb: fix issue with dialogs hidden by other windows") + // or QTBUG-46626. So LO has to set this itself to help some WMs. + if (!g_bNeedsWmHintsWindowGroup) + return; + g_bNeedsWmHintsWindowGroup = false; + + if (QGuiApplication::platformName() != "xcb") + return; + if (QVersionNumber::fromString(qVersion()) >= QVersionNumber(5, 12)) + return; + + xcb_connection_t* conn = QX11Info::connection(); + xcb_window_t win = asChild()->winId(); + + xcb_icccm_wm_hints_t hints; + + xcb_get_property_cookie_t prop_cookie = xcb_icccm_get_wm_hints_unchecked(conn, win); + if (!xcb_icccm_get_wm_hints_reply(conn, prop_cookie, &hints, nullptr)) + return; + + if (hints.flags & XCB_ICCCM_WM_HINT_WINDOW_GROUP) + return; + + if (g_aXcbClientLeaderAtom == 0) + { + const char* const leader_name = "WM_CLIENT_LEADER\0"; + xcb_intern_atom_cookie_t atom_cookie + = xcb_intern_atom(conn, 1, strlen(leader_name), leader_name); + xcb_intern_atom_reply_t* atom_reply = xcb_intern_atom_reply(conn, atom_cookie, nullptr); + if (!atom_reply) + return; + g_aXcbClientLeaderAtom = atom_reply->atom; + free(atom_reply); + } + + g_bNeedsWmHintsWindowGroup = true; + + prop_cookie = xcb_get_property(conn, 0, win, g_aXcbClientLeaderAtom, XCB_ATOM_WINDOW, 0, 1); + xcb_get_property_reply_t* prop_reply = xcb_get_property_reply(conn, prop_cookie, nullptr); + if (!prop_reply) + return; + + if (xcb_get_property_value_length(prop_reply) != 4) + { + free(prop_reply); + return; + } + + xcb_window_t leader = *static_cast(xcb_get_property_value(prop_reply)); + free(prop_reply); + + hints.flags |= XCB_ICCCM_WM_HINT_WINDOW_GROUP; + hints.window_group = leader; + xcb_icccm_set_wm_hints(conn, win, &hints); +#else + (void)this; // avoid loplugin:staticmethods +#endif +} + +Qt5Frame::~Qt5Frame() +{ + Qt5Instance* pInst = static_cast(GetSalData()->m_pInstance); + pInst->eraseFrame(this); + delete asChild(); + m_aSystemData.aShellWindow = 0; +} + +void Qt5Frame::Damage(sal_Int32 nExtentsX, sal_Int32 nExtentsY, sal_Int32 nExtentsWidth, + sal_Int32 nExtentsHeight) const +{ + m_pQWidget->update(scaledQRect(QRect(nExtentsX, nExtentsY, nExtentsWidth, nExtentsHeight), + 1 / devicePixelRatioF())); +} + +void Qt5Frame::InitQt5SvpGraphics(Qt5SvpGraphics* pQt5SvpGraphics) +{ + int width = 640; + int height = 480; + m_pSvpGraphics = pQt5SvpGraphics; + m_pSurface.reset(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)); + m_pSvpGraphics->setSurface(m_pSurface.get(), basegfx::B2IVector(width, height)); + cairo_surface_set_user_data(m_pSurface.get(), Qt5SvpGraphics::getDamageKey(), &m_aDamageHandler, + nullptr); +} + +SalGraphics* Qt5Frame::AcquireGraphics() +{ + if (m_bGraphicsInUse) + return nullptr; + + m_bGraphicsInUse = true; + + if (m_bUseCairo) + { + if (!m_pOurSvpGraphics || m_bGraphicsInvalid) + { + m_pOurSvpGraphics.reset(new Qt5SvpGraphics(this)); + InitQt5SvpGraphics(m_pOurSvpGraphics.get()); + m_bGraphicsInvalid = false; + } + return m_pOurSvpGraphics.get(); + } + else + { + if (!m_pQt5Graphics || m_bGraphicsInvalid) + { + m_pQt5Graphics.reset(new Qt5Graphics(this)); + m_pQImage.reset( + new QImage(m_pQWidget->size() * devicePixelRatioF(), Qt5_DefaultFormat32)); + m_pQImage->fill(Qt::transparent); + m_pQt5Graphics->ChangeQImage(m_pQImage.get()); + m_bGraphicsInvalid = false; + } + return m_pQt5Graphics.get(); + } +} + +void Qt5Frame::ReleaseGraphics(SalGraphics* pSalGraph) +{ + (void)pSalGraph; + if (m_bUseCairo) + assert(pSalGraph == m_pOurSvpGraphics.get()); + else + assert(pSalGraph == m_pQt5Graphics.get()); + m_bGraphicsInUse = false; +} + +bool Qt5Frame::PostEvent(std::unique_ptr pData) +{ + Qt5Instance* pInst = static_cast(GetSalData()->m_pInstance); + pInst->PostEvent(this, pData.release(), SalEvent::UserEvent); + return true; +} + +QWidget* Qt5Frame::asChild() const { return m_pTopLevel ? m_pTopLevel : m_pQWidget; } + +qreal Qt5Frame::devicePixelRatioF() const { return asChild()->devicePixelRatioF(); } + +bool Qt5Frame::isWindow() const { return asChild()->isWindow(); } + +QWindow* Qt5Frame::windowHandle() const +{ + // set attribute 'Qt::WA_NativeWindow' first to make sure a window handle actually exists + QWidget* pChild = asChild(); + pChild->setAttribute(Qt::WA_NativeWindow); + return pChild->windowHandle(); +} + +QScreen* Qt5Frame::screen() const +{ + QWindow* const pWindow = windowHandle(); + return pWindow ? pWindow->screen() : nullptr; +} + +bool Qt5Frame::isMinimized() const { return asChild()->isMinimized(); } + +bool Qt5Frame::isMaximized() const { return asChild()->isMaximized(); } + +void Qt5Frame::SetWindowStateImpl(Qt::WindowStates eState) +{ + return asChild()->setWindowState(eState); +} + +void Qt5Frame::SetTitle(const OUString& rTitle) +{ + m_pQWidget->window()->setWindowTitle(toQString(rTitle)); +} + +void Qt5Frame::SetIcon(sal_uInt16 nIcon) +{ + if (m_nStyle + & (SalFrameStyleFlags::PLUG | SalFrameStyleFlags::SYSTEMCHILD + | SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::INTRO + | SalFrameStyleFlags::OWNERDRAWDECORATION) + || !isWindow()) + return; + + QString appicon; + + if (nIcon == SV_ICON_ID_TEXT) + appicon = "libreoffice-writer"; + else if (nIcon == SV_ICON_ID_SPREADSHEET) + appicon = "libreoffice-calc"; + else if (nIcon == SV_ICON_ID_DRAWING) + appicon = "libreoffice-draw"; + else if (nIcon == SV_ICON_ID_PRESENTATION) + appicon = "libreoffice-impress"; + else if (nIcon == SV_ICON_ID_DATABASE) + appicon = "libreoffice-base"; + else if (nIcon == SV_ICON_ID_FORMULA) + appicon = "libreoffice-math"; + else + appicon = "libreoffice-startcenter"; + + QIcon aIcon = QIcon::fromTheme(appicon); + m_pQWidget->window()->setWindowIcon(aIcon); +} + +void Qt5Frame::SetMenu(SalMenu* pMenu) { m_pSalMenu = static_cast(pMenu); } + +void Qt5Frame::DrawMenuBar() { /* not needed */} + +void Qt5Frame::SetExtendedFrameStyle(SalExtStyle /*nExtStyle*/) { /* not needed */} + +void Qt5Frame::Show(bool bVisible, bool /*bNoActivate*/) +{ + assert(m_pQWidget); + + SetDefaultSize(); + SetDefaultPos(); + + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, bVisible]() { asChild()->setVisible(bVisible); }); +} + +void Qt5Frame::SetMinClientSize(long nWidth, long nHeight) +{ + if (!isChild()) + { + const qreal fRatio = devicePixelRatioF(); + asChild()->setMinimumSize(round(nWidth / fRatio), round(nHeight / fRatio)); + } +} + +void Qt5Frame::SetMaxClientSize(long nWidth, long nHeight) +{ + if (!isChild()) + { + const qreal fRatio = devicePixelRatioF(); + asChild()->setMaximumSize(round(nWidth / fRatio), round(nHeight / fRatio)); + } +} + +void Qt5Frame::SetDefaultPos() +{ + if (!m_bDefaultPos) + return; + + // center on parent + if (m_pParent) + { + const qreal fRatio = devicePixelRatioF(); + QWidget* const pWindow = m_pParent->GetQWidget()->window(); + QWidget* const pWidget = asChild(); + QPoint aPos = pWindow->rect().center() - pWidget->rect().center(); + SetPosSize(round(aPos.x() * fRatio), round(aPos.y() * fRatio), 0, 0, + SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y); + assert(!m_bDefaultPos); + } + else + m_bDefaultPos = false; +} + +Size Qt5Frame::CalcDefaultSize() +{ + assert(isWindow()); + + Size aSize; + if (!m_bFullScreen) + { + const QScreen* pScreen = screen(); + SAL_WNODEPRECATED_DECLARATIONS_PUSH + aSize = bestmaxFrameSizeForScreenSize( + toSize(pScreen ? pScreen->size() : QApplication::desktop()->screenGeometry(0).size())); + SAL_WNODEPRECATED_DECLARATIONS_POP + } + else + { + if (!m_bFullScreenSpanAll) + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + aSize = toSize( + QApplication::desktop()->screenGeometry(maGeometry.nDisplayScreenNumber).size()); + SAL_WNODEPRECATED_DECLARATIONS_POP + } + else + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); + SAL_WNODEPRECATED_DECLARATIONS_POP + aSize = toSize(QApplication::screens()[nLeftScreen]->availableVirtualGeometry().size()); + } + } + + return aSize; +} + +void Qt5Frame::SetDefaultSize() +{ + if (!m_bDefaultSize) + return; + + Size aDefSize = CalcDefaultSize(); + SetPosSize(0, 0, aDefSize.Width(), aDefSize.Height(), + SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT); + assert(!m_bDefaultSize); +} + +void Qt5Frame::SetPosSize(long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags) +{ + if (!isWindow() || isChild(true, false)) + return; + + if (nFlags & (SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT)) + { + if (isChild(false) || !m_pQWidget->isMaximized()) + { + if (!(nFlags & SAL_FRAME_POSSIZE_WIDTH)) + nWidth = maGeometry.nWidth; + else if (!(nFlags & SAL_FRAME_POSSIZE_HEIGHT)) + nHeight = maGeometry.nHeight; + + if (nWidth > 0 && nHeight > 0) + { + m_bDefaultSize = false; + const int nNewWidth = round(nWidth / devicePixelRatioF()); + const int nNewHeight = round(nHeight / devicePixelRatioF()); + if (m_nStyle & SalFrameStyleFlags::SIZEABLE) + asChild()->resize(nNewWidth, nNewHeight); + else + asChild()->setFixedSize(nNewWidth, nNewHeight); + } + + // assume the resize happened + // needed for calculations and will eventually be corrected by events + if (nWidth > 0) + maGeometry.nWidth = nWidth; + if (nHeight > 0) + maGeometry.nHeight = nHeight; + } + } + + if (nFlags & (SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y)) + { + if (m_pParent) + { + const SalFrameGeometry& aParentGeometry = m_pParent->maGeometry; + if (QGuiApplication::isRightToLeft()) + nX = aParentGeometry.nX + aParentGeometry.nWidth - nX - maGeometry.nWidth - 1; + else + nX += aParentGeometry.nX; + nY += aParentGeometry.nY; + + Qt5MainWindow* pTopLevel = m_pParent->GetTopLevelWindow(); + if (pTopLevel && pTopLevel->menuBar() && pTopLevel->menuBar()->isVisible()) + nY += round(pTopLevel->menuBar()->geometry().height() * devicePixelRatioF()); + } + + if (!(nFlags & SAL_FRAME_POSSIZE_X)) + nX = maGeometry.nX; + else if (!(nFlags & SAL_FRAME_POSSIZE_Y)) + nY = maGeometry.nY; + + // assume the reposition happened + // needed for calculations and will eventually be corrected by events later + maGeometry.nX = nX; + maGeometry.nY = nY; + + m_bDefaultPos = false; + asChild()->move(round(nX / devicePixelRatioF()), round(nY / devicePixelRatioF())); + } +} + +void Qt5Frame::GetClientSize(long& rWidth, long& rHeight) +{ + rWidth = round(m_pQWidget->width() * devicePixelRatioF()); + rHeight = round(m_pQWidget->height() * devicePixelRatioF()); +} + +void Qt5Frame::GetWorkArea(tools::Rectangle& rRect) +{ + if (!isWindow()) + return; + QScreen* pScreen = screen(); + if (!pScreen) + return; + + QSize aSize = pScreen->availableVirtualSize() * devicePixelRatioF(); + rRect = tools::Rectangle(0, 0, aSize.width(), aSize.height()); +} + +SalFrame* Qt5Frame::GetParent() const { return m_pParent; } + +void Qt5Frame::SetModal(bool bModal) +{ + if (isWindow()) + { + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->RunInMainThread([this, bModal]() { + + QWidget* const pChild = asChild(); + const bool bWasVisible = pChild->isVisible(); + + // modality change is only effective if the window is hidden + if (bWasVisible) + pChild->hide(); + + pChild->setWindowModality(bModal ? Qt::WindowModal : Qt::NonModal); + + if (bWasVisible) + pChild->show(); + }); + } +} + +bool Qt5Frame::GetModal() const { return isWindow() && windowHandle()->isModal(); } + +void Qt5Frame::SetWindowState(const SalFrameState* pState) +{ + if (!isWindow() || !pState || isChild(true, false)) + return; + + const WindowStateMask nMaxGeometryMask + = WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width | WindowStateMask::Height + | WindowStateMask::MaximizedX | WindowStateMask::MaximizedY + | WindowStateMask::MaximizedWidth | WindowStateMask::MaximizedHeight; + + if ((pState->mnMask & WindowStateMask::State) && (pState->mnState & WindowStateState::Maximized) + && !isMaximized() && (pState->mnMask & nMaxGeometryMask) == nMaxGeometryMask) + { + const qreal fRatio = devicePixelRatioF(); + QWidget* const pChild = asChild(); + pChild->resize(ceil(pState->mnWidth / fRatio), ceil(pState->mnHeight / fRatio)); + pChild->move(ceil(pState->mnX / fRatio), ceil(pState->mnY / fRatio)); + SetWindowStateImpl(Qt::WindowMaximized); + } + else if (pState->mnMask + & (WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width + | WindowStateMask::Height)) + { + sal_uInt16 nPosSizeFlags = 0; + if (pState->mnMask & WindowStateMask::X) + nPosSizeFlags |= SAL_FRAME_POSSIZE_X; + if (pState->mnMask & WindowStateMask::Y) + nPosSizeFlags |= SAL_FRAME_POSSIZE_Y; + if (pState->mnMask & WindowStateMask::Width) + nPosSizeFlags |= SAL_FRAME_POSSIZE_WIDTH; + if (pState->mnMask & WindowStateMask::Height) + nPosSizeFlags |= SAL_FRAME_POSSIZE_HEIGHT; + SetPosSize(pState->mnX, pState->mnY, pState->mnWidth, pState->mnHeight, nPosSizeFlags); + } + else if (pState->mnMask & WindowStateMask::State && !isChild()) + { + if (pState->mnState & WindowStateState::Maximized) + SetWindowStateImpl(Qt::WindowMaximized); + else if (pState->mnState & WindowStateState::Minimized) + SetWindowStateImpl(Qt::WindowMinimized); + else + SetWindowStateImpl(Qt::WindowNoState); + } +} + +bool Qt5Frame::GetWindowState(SalFrameState* pState) +{ + pState->mnState = WindowStateState::Normal; + pState->mnMask = WindowStateMask::State; + if (isMinimized() /*|| !windowHandle()*/) + pState->mnState |= WindowStateState::Minimized; + else if (isMaximized()) + { + pState->mnState |= WindowStateState::Maximized; + } + else + { + // geometry() is the drawable area, which is wanted here + QRect rect = scaledQRect(asChild()->geometry(), devicePixelRatioF()); + pState->mnX = rect.x(); + pState->mnY = rect.y(); + pState->mnWidth = rect.width(); + pState->mnHeight = rect.height(); + pState->mnMask |= WindowStateMask::X | WindowStateMask::Y | WindowStateMask::Width + | WindowStateMask::Height; + } + + return true; +} + +void Qt5Frame::ShowFullScreen(bool bFullScreen, sal_Int32 nScreen) +{ + // only top-level windows can go fullscreen + assert(m_pTopLevel); + + if (m_bFullScreen == bFullScreen) + return; + + m_bFullScreen = bFullScreen; + m_bFullScreenSpanAll = m_bFullScreen && (nScreen < 0); + + // show it if it isn't shown yet + if (!isWindow()) + m_pTopLevel->show(); + + if (m_bFullScreen) + { + m_aRestoreGeometry = m_pTopLevel->geometry(); + m_nRestoreScreen = maGeometry.nDisplayScreenNumber; + SetScreenNumber(m_bFullScreenSpanAll ? m_nRestoreScreen : nScreen); + if (!m_bFullScreenSpanAll) + windowHandle()->showFullScreen(); + else + windowHandle()->showNormal(); + } + else + { + SetScreenNumber(m_nRestoreScreen); + windowHandle()->showNormal(); + m_pTopLevel->setGeometry(m_aRestoreGeometry); + } +} + +void Qt5Frame::StartPresentation(bool bStart) +{ +// meh - so there's no Qt platform independent solution +// https://forum.qt.io/topic/38504/solved-qdialog-in-fullscreen-disable-os-screensaver +#if QT5_USING_X11 + std::optional aRootWindow; + std::optional aDisplay; + + if (QX11Info::isPlatformX11()) + { + aRootWindow = QX11Info::appRootWindow(); + aDisplay = QX11Info::display(); + } + + m_ScreenSaverInhibitor.inhibit(bStart, "presentation", QX11Info::isPlatformX11(), aRootWindow, + aDisplay); +#else + (void)bStart; +#endif +} + +void Qt5Frame::SetAlwaysOnTop(bool bOnTop) +{ + QWidget* const pWidget = asChild(); + const Qt::WindowFlags flags = pWidget->windowFlags(); + if (bOnTop) + pWidget->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); + else + pWidget->setWindowFlags(flags & ~(Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint)); +} + +void Qt5Frame::ToTop(SalFrameToTop nFlags) +{ + QWidget* const pWidget = asChild(); + if (isWindow() && !(nFlags & SalFrameToTop::GrabFocusOnly)) + pWidget->raise(); + if ((nFlags & SalFrameToTop::RestoreWhenMin) || (nFlags & SalFrameToTop::ForegroundTask)) + pWidget->activateWindow(); + else if ((nFlags & SalFrameToTop::GrabFocus) || (nFlags & SalFrameToTop::GrabFocusOnly)) + { + pWidget->activateWindow(); + pWidget->setFocus(); + } +} + +void Qt5Frame::SetPointer(PointerStyle ePointerStyle) +{ + QWindow* pWindow = m_pQWidget->window()->windowHandle(); + if (!pWindow) + return; + if (ePointerStyle == m_ePointerStyle) + return; + m_ePointerStyle = ePointerStyle; + + pWindow->setCursor(static_cast(GetSalData())->getCursor(ePointerStyle)); +} + +void Qt5Frame::CaptureMouse(bool bMouse) +{ + static const char* pEnv = getenv("SAL_NO_MOUSEGRABS"); + if (pEnv && *pEnv) + return; + + if (bMouse) + m_pQWidget->grabMouse(); + else + m_pQWidget->releaseMouse(); +} + +void Qt5Frame::SetPointerPos(long nX, long nY) +{ + // some cursor already exists (and it has m_ePointerStyle shape) + // so here we just reposition it + QCursor::setPos(m_pQWidget->mapToGlobal(QPoint(nX, nY))); +} + +void Qt5Frame::Flush() +{ + // was: QGuiApplication::sync(); + // but FIXME it causes too many issues, figure out sth better + + // unclear if we need to also flush cairo surface - gtk3 backend + // does not do it. QPainter in Qt5Widget::paintEvent() is + // destroyed, so that state should be safely flushed. +} + +bool Qt5Frame::ShowTooltip(const OUString& rText, const tools::Rectangle& rHelpArea) +{ + QRect aHelpArea(toQRect(rHelpArea)); + if (QGuiApplication::isRightToLeft()) + aHelpArea.moveLeft(maGeometry.nWidth - aHelpArea.width() - aHelpArea.left() - 1); + QToolTip::showText(QCursor::pos(), toQString(rText), m_pQWidget, aHelpArea); + return true; +} + +void Qt5Frame::SetInputContext(SalInputContext* pContext) +{ + if (!pContext) + return; + + if (!(pContext->mnOptions & InputContextFlags::Text)) + return; + + m_pQWidget->setAttribute(Qt::WA_InputMethodEnabled); +} + +void Qt5Frame::EndExtTextInput(EndExtTextInputFlags /*nFlags*/) +{ + Qt5Widget* pQt5Widget = static_cast(m_pQWidget); + if (pQt5Widget) + pQt5Widget->endExtTextInput(); +} + +OUString Qt5Frame::GetKeyName(sal_uInt16 nKeyCode) +{ + vcl::KeyCode vclKeyCode(nKeyCode); + int nCode = vclKeyCode.GetCode(); + int nRetCode = 0; + + if (nCode >= KEY_0 && nCode <= KEY_9) + nRetCode = (nCode - KEY_0) + Qt::Key_0; + else if (nCode >= KEY_A && nCode <= KEY_Z) + nRetCode = (nCode - KEY_A) + Qt::Key_A; + else if (nCode >= KEY_F1 && nCode <= KEY_F26) + nRetCode = (nCode - KEY_F1) + Qt::Key_F1; + else + { + switch (nCode) + { + case KEY_DOWN: + nRetCode = Qt::Key_Down; + break; + case KEY_UP: + nRetCode = Qt::Key_Up; + break; + case KEY_LEFT: + nRetCode = Qt::Key_Left; + break; + case KEY_RIGHT: + nRetCode = Qt::Key_Right; + break; + case KEY_HOME: + nRetCode = Qt::Key_Home; + break; + case KEY_END: + nRetCode = Qt::Key_End; + break; + case KEY_PAGEUP: + nRetCode = Qt::Key_PageUp; + break; + case KEY_PAGEDOWN: + nRetCode = Qt::Key_PageDown; + break; + case KEY_RETURN: + nRetCode = Qt::Key_Return; + break; + case KEY_ESCAPE: + nRetCode = Qt::Key_Escape; + break; + case KEY_TAB: + nRetCode = Qt::Key_Tab; + break; + case KEY_BACKSPACE: + nRetCode = Qt::Key_Backspace; + break; + case KEY_SPACE: + nRetCode = Qt::Key_Space; + break; + case KEY_INSERT: + nRetCode = Qt::Key_Insert; + break; + case KEY_DELETE: + nRetCode = Qt::Key_Delete; + break; + case KEY_ADD: + nRetCode = Qt::Key_Plus; + break; + case KEY_SUBTRACT: + nRetCode = Qt::Key_Minus; + break; + case KEY_MULTIPLY: + nRetCode = Qt::Key_Asterisk; + break; + case KEY_DIVIDE: + nRetCode = Qt::Key_Slash; + break; + case KEY_POINT: + nRetCode = Qt::Key_Period; + break; + case KEY_COMMA: + nRetCode = Qt::Key_Comma; + break; + case KEY_LESS: + nRetCode = Qt::Key_Less; + break; + case KEY_GREATER: + nRetCode = Qt::Key_Greater; + break; + case KEY_EQUAL: + nRetCode = Qt::Key_Equal; + break; + case KEY_FIND: + nRetCode = Qt::Key_Find; + break; + case KEY_CONTEXTMENU: + nRetCode = Qt::Key_Menu; + break; + case KEY_HELP: + nRetCode = Qt::Key_Help; + break; + case KEY_UNDO: + nRetCode = Qt::Key_Undo; + break; + case KEY_REPEAT: + nRetCode = Qt::Key_Redo; + break; + case KEY_TILDE: + nRetCode = Qt::Key_AsciiTilde; + break; + case KEY_QUOTELEFT: + nRetCode = Qt::Key_QuoteLeft; + break; + case KEY_BRACKETLEFT: + nRetCode = Qt::Key_BracketLeft; + break; + case KEY_BRACKETRIGHT: + nRetCode = Qt::Key_BracketRight; + break; + case KEY_SEMICOLON: + nRetCode = Qt::Key_Semicolon; + break; + + // Special cases + case KEY_COPY: + nRetCode = Qt::Key_Copy; + break; + case KEY_CUT: + nRetCode = Qt::Key_Cut; + break; + case KEY_PASTE: + nRetCode = Qt::Key_Paste; + break; + case KEY_OPEN: + nRetCode = Qt::Key_Open; + break; + } + } + + if (vclKeyCode.IsShift()) + nRetCode += Qt::SHIFT; + if (vclKeyCode.IsMod1()) + nRetCode += Qt::CTRL; + if (vclKeyCode.IsMod2()) + nRetCode += Qt::ALT; + + QKeySequence keySeq(nRetCode); + OUString sKeyName = toOUString(keySeq.toString()); + + return sKeyName; +} + +bool Qt5Frame::MapUnicodeToKeyCode(sal_Unicode /*aUnicode*/, LanguageType /*aLangType*/, + vcl::KeyCode& /*rKeyCode*/) +{ + // not supported yet + return false; +} + +LanguageType Qt5Frame::GetInputLanguage() +{ + // fallback + return LANGUAGE_DONTKNOW; +} + +static Color toColor(const QColor& rColor) +{ + return Color(rColor.red(), rColor.green(), rColor.blue()); +} + +void Qt5Frame::UpdateSettings(AllSettings& rSettings) +{ + if (Qt5Data::noNativeControls()) + return; + + StyleSettings style(rSettings.GetStyleSettings()); + + // General settings + QPalette pal = QApplication::palette(); + + style.SetToolbarIconSize(ToolbarIconSize::Large); + + 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)); + Color aHighText = toColor(pal.color(QPalette::Active, QPalette::HighlightedText)); + Color aLink = toColor(pal.color(QPalette::Active, QPalette::Link)); + Color aVisitedLink = toColor(pal.color(QPalette::Active, QPalette::LinkVisited)); + + style.SetSkipDisabledInMenus(true); + + // Foreground + style.SetRadioCheckTextColor(aFore); + style.SetLabelTextColor(aFore); + style.SetDialogTextColor(aFore); + style.SetGroupTextColor(aFore); + + // Text + style.SetFieldTextColor(aText); + style.SetFieldRolloverTextColor(aText); + style.SetWindowTextColor(aText); + style.SetToolTextColor(aText); + + // Base + style.SetFieldColor(aBase); + style.SetWindowColor(aBase); + style.SetActiveTabColor(aBase); + style.SetAlternatingRowColor(toColor(pal.color(QPalette::Active, QPalette::AlternateBase))); + + // Buttons + style.SetDefaultButtonTextColor(aButn); + style.SetButtonTextColor(aButn); + style.SetDefaultActionButtonTextColor(aButn); + style.SetActionButtonTextColor(aButn); + style.SetFlatButtonTextColor(aButn); + style.SetDefaultButtonRolloverTextColor(aButn); + style.SetButtonRolloverTextColor(aButn); + style.SetDefaultActionButtonRolloverTextColor(aButn); + style.SetActionButtonRolloverTextColor(aButn); + style.SetFlatButtonRolloverTextColor(aButn); + style.SetDefaultButtonPressedRolloverTextColor(aButn); + style.SetButtonPressedRolloverTextColor(aButn); + style.SetDefaultActionButtonPressedRolloverTextColor(aButn); + style.SetActionButtonPressedRolloverTextColor(aButn); + style.SetFlatButtonPressedRolloverTextColor(aButn); + + // Tabs + style.SetTabTextColor(aButn); + style.SetTabRolloverTextColor(aButn); + style.SetTabHighlightTextColor(aButn); + + // Disable color + style.SetDisableColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); + + // Background + style.BatchSetBackgrounds(aBack); + style.SetInactiveTabColor(aBack); + + // Workspace + style.SetWorkspaceColor(aMid); + + // Selection + style.SetHighlightColor(aHigh); + style.SetHighlightTextColor(aHighText); + style.SetActiveColor(aHigh); + style.SetActiveTextColor(aHighText); + + // Links + style.SetLinkColor(aLink); + style.SetVisitedLinkColor(aVisitedLink); + + // Tooltip + style.SetHelpColor(toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipBase))); + style.SetHelpTextColor( + toColor(QToolTip::palette().color(QPalette::Active, QPalette::ToolTipText))); + + const int flash_time = QApplication::cursorFlashTime(); + style.SetCursorBlinkTime(flash_time != 0 ? flash_time / 2 : STYLE_CURSOR_NOBLINKTIME); + + // Menu + std::unique_ptr pMenuBar = std::make_unique(); + 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)); + + style.SetMenuTextColor(aMenuFore); + style.SetMenuBarTextColor(style.GetPersonaMenuBarTextColor().value_or(aMenuFore)); + style.SetMenuColor(aMenuBack); + style.SetMenuBarColor(aMenuBack); + style.SetMenuHighlightColor(toColor(qMenuCG.color(QPalette::Highlight))); + style.SetMenuHighlightTextColor(toColor(qMenuCG.color(QPalette::HighlightedText))); + + // set special menubar highlight text color + if (QApplication::style()->inherits("HighContrastStyle")) + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor + = toColor(qMenuCG.color(QPalette::HighlightedText)); + else + ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor = aMenuFore; + + // set menubar rollover color + if (pMenuBar->style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) + { + style.SetMenuBarRolloverColor(toColor(qMenuCG.color(QPalette::Highlight))); + style.SetMenuBarRolloverTextColor(ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor); + } + else + { + style.SetMenuBarRolloverColor(aMenuBack); + style.SetMenuBarRolloverTextColor(aMenuFore); + } + style.SetMenuBarHighlightTextColor(style.GetMenuHighlightTextColor()); + + // Icon theme + style.SetPreferredIconTheme(toOUString(QIcon::themeName())); + + // Scroll bar size + style.SetScrollBarSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)); + style.SetMinThumbSize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarSliderMin)); + + // These colors are used for the ruler text and marks + style.SetShadowColor(toColor(pal.color(QPalette::Disabled, QPalette::WindowText))); + style.SetDarkShadowColor(toColor(pal.color(QPalette::Inactive, QPalette::WindowText))); + + m_bGraphicsInvalid = true; + rSettings.SetStyleSettings(style); +} + +void Qt5Frame::Beep() { QApplication::beep(); } + +SalFrame::SalPointerState Qt5Frame::GetPointerState() +{ + SalPointerState aState; + aState.maPos = toPoint(QCursor::pos() * devicePixelRatioF()); + aState.maPos.Move(-maGeometry.nX, -maGeometry.nY); + aState.mnState = GetMouseModCode(QGuiApplication::mouseButtons()) + | GetKeyModCode(QGuiApplication::keyboardModifiers()); + return aState; +} + +KeyIndicatorState Qt5Frame::GetIndicatorState() { return KeyIndicatorState(); } + +void Qt5Frame::SimulateKeyPress(sal_uInt16 nKeyCode) +{ + SAL_WARN("vcl.qt5", "missing simulate keypress " << nKeyCode); +} + +void Qt5Frame::SetParent(SalFrame* pNewParent) { m_pParent = static_cast(pNewParent); } + +bool Qt5Frame::SetPluginParent(SystemParentData* /*pNewParent*/) +{ + //FIXME: no SetPluginParent impl. for qt5 + return false; +} + +void Qt5Frame::ResetClipRegion() { m_bNullRegion = true; } + +void Qt5Frame::BeginSetClipRegion(sal_uInt32) +{ + m_aRegion = QRegion(QRect(QPoint(0, 0), m_pQWidget->size())); +} + +void Qt5Frame::UnionClipRegion(long nX, long nY, long nWidth, long nHeight) +{ + m_aRegion + = m_aRegion.united(scaledQRect(QRect(nX, nY, nWidth, nHeight), 1 / devicePixelRatioF())); +} + +void Qt5Frame::EndSetClipRegion() { m_bNullRegion = false; } + +void Qt5Frame::SetScreenNumber(unsigned int nScreen) +{ + if (isWindow()) + { + QWindow* const pWindow = windowHandle(); + if (pWindow) + { + QList screens = QApplication::screens(); + if (static_cast(nScreen) < screens.size() || m_bFullScreenSpanAll) + { + QRect screenGeo; + + if (!m_bFullScreenSpanAll) + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + screenGeo = QApplication::desktop()->screenGeometry(nScreen); + SAL_WNODEPRECATED_DECLARATIONS_POP + pWindow->setScreen(QApplication::screens()[nScreen]); + } + else // special case: fullscreen over all available screens + { + assert(m_bFullScreen); + // left-most screen + SAL_WNODEPRECATED_DECLARATIONS_PUSH + int nLeftScreen = QApplication::desktop()->screenNumber(QPoint(0, 0)); + SAL_WNODEPRECATED_DECLARATIONS_POP + // entire virtual desktop + screenGeo = QApplication::screens()[nLeftScreen]->availableVirtualGeometry(); + pWindow->setScreen(QApplication::screens()[nLeftScreen]); + pWindow->setGeometry(screenGeo); + nScreen = nLeftScreen; + } + + // setScreen by itself has no effect, explicitly move the widget to + // the new screen + asChild()->move(screenGeo.topLeft()); + } + else + { + // index outta bounds, use primary screen + QScreen* primaryScreen = QApplication::primaryScreen(); + pWindow->setScreen(primaryScreen); + nScreen = static_cast(screenNumber(primaryScreen)); + } + + maGeometry.nDisplayScreenNumber = nScreen; + } + } +} + +void Qt5Frame::SetApplicationID(const OUString& rWMClass) +{ +#if QT5_USING_X11 + if (QGuiApplication::platformName() != "xcb" || !m_pTopLevel) + return; + + OString aResClass = OUStringToOString(rWMClass, RTL_TEXTENCODING_ASCII_US); + const char* pResClass + = !aResClass.isEmpty() ? aResClass.getStr() : SalGenericSystem::getFrameClassName(); + OString aResName = SalGenericSystem::getFrameResName(); + + // the WM_CLASS data consists of two concatenated cstrings, including the terminating '\0' chars + const uint32_t data_len = aResName.getLength() + 1 + strlen(pResClass) + 1; + char* data = new char[data_len]; + memcpy(data, aResName.getStr(), aResName.getLength() + 1); + memcpy(data + aResName.getLength() + 1, pResClass, strlen(pResClass) + 1); + + xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, m_pTopLevel->winId(), + XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 8, data_len, data); + delete[] data; +#else + (void)rWMClass; +#endif +} + +// Drag'n'drop foo + +void Qt5Frame::registerDragSource(Qt5DragSource* pDragSource) +{ + assert(!m_pDragSource); + m_pDragSource = pDragSource; +} + +void Qt5Frame::deregisterDragSource(Qt5DragSource const* pDragSource) +{ + assert(m_pDragSource == pDragSource); + (void)pDragSource; + m_pDragSource = nullptr; +} + +void Qt5Frame::registerDropTarget(Qt5DropTarget* pDropTarget) +{ + assert(!m_pDropTarget); + m_pDropTarget = pDropTarget; + m_pQWidget->setAcceptDrops(true); +} + +void Qt5Frame::deregisterDropTarget(Qt5DropTarget const* pDropTarget) +{ + assert(m_pDropTarget == pDropTarget); + (void)pDropTarget; + m_pDropTarget = nullptr; +} + +static css::uno::Reference +lcl_getXTransferable(const QMimeData* pMimeData) +{ + css::uno::Reference xTransferable; + const Qt5MimeData* pQt5MimeData = dynamic_cast(pMimeData); + if (!pQt5MimeData) + xTransferable = new Qt5DnDTransferable(pMimeData); + else + xTransferable = pQt5MimeData->xTransferable(); + return xTransferable; +} + +static sal_Int8 lcl_getUserDropAction(const QDropEvent* pEvent, const sal_Int8 nSourceActions, + const QMimeData* pMimeData) +{ + // we completely ignore all proposals by the Qt event, as they don't + // match at all with the preferred LO DnD actions. + + // check the key modifiers to detect a user-overridden DnD action + const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers(); + sal_Int8 nUserDropAction = 0; + if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + else if ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY; + else if ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier)) + nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK; + nUserDropAction &= nSourceActions; + + // select the default DnD action, if there isn't a user preference + if (0 == nUserDropAction) + { + // default LO internal action is move, but default external action is copy + nUserDropAction = dynamic_cast(pMimeData) + ? css::datatransfer::dnd::DNDConstants::ACTION_MOVE + : css::datatransfer::dnd::DNDConstants::ACTION_COPY; + nUserDropAction &= nSourceActions; + + // if the default doesn't match any allowed source action, fall back to the + // preferred of all allowed source actions + if (0 == nUserDropAction) + nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions)); + + // this is "our" preference, but actually we would even prefer any default, + // if there is any + nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT; + } + return nUserDropAction; +} + +void Qt5Frame::handleDragMove(QDragMoveEvent* pEvent) +{ + assert(m_pDropTarget); + + // prepare our suggested drop action for the drop target + const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); + const QMimeData* pMimeData = pEvent->mimeData(); + const sal_Int8 nUserDropAction = lcl_getUserDropAction(pEvent, nSourceActions, pMimeData); + const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); + + css::datatransfer::dnd::DropTargetDragEnterEvent aEvent; + aEvent.Source = static_cast(m_pDropTarget); + aEvent.Context = static_cast(m_pDropTarget); + aEvent.LocationX = aPos.X(); + aEvent.LocationY = aPos.Y(); + aEvent.DropAction = nUserDropAction; + aEvent.SourceActions = nSourceActions; + + // ask the drop target to accept our drop action + if (!m_bInDrag) + { + aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors(); + m_pDropTarget->fire_dragEnter(aEvent); + m_bInDrag = true; + } + else + m_pDropTarget->fire_dragOver(aEvent); + + // the drop target accepted our drop action => inform Qt + if (m_pDropTarget->proposedDropAction() != 0) + { + pEvent->setDropAction(getPreferredDropAction(m_pDropTarget->proposedDropAction())); + pEvent->accept(); + } + else // or maybe someone else likes it? + pEvent->ignore(); +} + +void Qt5Frame::handleDrop(QDropEvent* pEvent) +{ + assert(m_pDropTarget); + + // prepare our suggested drop action for the drop target + const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions()); + const sal_Int8 nUserDropAction + = lcl_getUserDropAction(pEvent, nSourceActions, pEvent->mimeData()); + const Point aPos = toPoint(pEvent->pos() * devicePixelRatioF()); + + css::datatransfer::dnd::DropTargetDropEvent aEvent; + aEvent.Source = static_cast(m_pDropTarget); + aEvent.Context = static_cast(m_pDropTarget); + aEvent.LocationX = aPos.X(); + aEvent.LocationY = aPos.Y(); + aEvent.SourceActions = nSourceActions; + aEvent.DropAction = nUserDropAction; + aEvent.Transferable = lcl_getXTransferable(pEvent->mimeData()); + + // ask the drop target to accept our drop action + m_pDropTarget->fire_drop(aEvent); + m_bInDrag = false; + + const bool bDropSuccessful = m_pDropTarget->dropSuccessful(); + const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction(); + + // inform the drag source of the drag-origin frame of the drop result + if (pEvent->source()) + { + Qt5Widget* pWidget = dynamic_cast(pEvent->source()); + assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself + if (pWidget) + pWidget->frame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful); + } + + // the drop target accepted our drop action => inform Qt + if (bDropSuccessful) + { + pEvent->setDropAction(getPreferredDropAction(nDropAction)); + pEvent->accept(); + } + else // or maybe someone else likes it? + pEvent->ignore(); +} + +void Qt5Frame::handleDragLeave() +{ + css::datatransfer::dnd::DropTargetEvent aEvent; + aEvent.Source = static_cast(m_pDropTarget); + m_pDropTarget->fire_dragExit(aEvent); + m_bInDrag = false; +} + +cairo_t* Qt5Frame::getCairoContext() const +{ + cairo_t* cr = nullptr; + if (m_bUseCairo) + { + cr = cairo_create(m_pSurface.get()); + assert(cr); + } + return cr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics.cxx b/vcl/qt5/Qt5Graphics.cxx new file mode 100644 index 000000000..34f610812 --- /dev/null +++ b/vcl/qt5/Qt5Graphics.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +Qt5Graphics::Qt5Graphics( Qt5Frame *pFrame, QImage *pQImage ) + : m_pFrame( pFrame ) + , m_pQImage( pQImage ) + , m_aLineColor( 0x00, 0x00, 0x00 ) + , m_aFillColor( 0xFF, 0xFF, 0XFF ) + , m_eCompositionMode( QPainter::CompositionMode_SourceOver ) + , m_pFontCollection( nullptr ) + , m_pTextStyle{ nullptr, } + , m_aTextColor( 0x00, 0x00, 0x00 ) +{ + ResetClipRegion(); + + if (!initWidgetDrawBackends(false)) + { + if (!Qt5Data::noNativeControls()) + m_pWidgetDraw.reset(new Qt5Graphics_Controls(*this)); + } + if (m_pFrame) + setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); +} + +Qt5Graphics::~Qt5Graphics() { ReleaseFonts(); } + +void Qt5Graphics::ChangeQImage(QImage* pQImage) +{ + m_pQImage = pQImage; + ResetClipRegion(); +} + +SalGraphicsImpl* Qt5Graphics::GetImpl() const { return nullptr; } + +SystemGraphicsData Qt5Graphics::GetGraphicsData() const { return SystemGraphicsData(); } + +bool Qt5Graphics::supportsOperation(OutDevSupportType eType) const +{ + switch (eType) + { + case OutDevSupportType::B2DDraw: + case OutDevSupportType::TransparentRect: + return true; + default: + return false; + } +} + +#if ENABLE_CAIRO_CANVAS + +bool Qt5Graphics::SupportsCairo() const { return false; } + +cairo::SurfaceSharedPtr +Qt5Graphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& /*rSurface*/) const +{ + return nullptr; +} + +cairo::SurfaceSharedPtr Qt5Graphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int /*x*/, + int /*y*/, int /*width*/, int /*height*/) const +{ + return nullptr; +} + +cairo::SurfaceSharedPtr Qt5Graphics::CreateBitmapSurface(const OutputDevice& /*rRefDevice*/, + const BitmapSystemData& /*rData*/, + const Size& /*rSize*/) const +{ + return nullptr; +} + +css::uno::Any Qt5Graphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& /*rSurface*/, + const basegfx::B2ISize& /*rSize*/) const +{ + return css::uno::Any(); +} + +SystemFontData Qt5Graphics::GetSysFontData(int /*nFallbacklevel*/) const +{ + return SystemFontData(); +} + +#endif + +void Qt5Graphics::handleDamage(const tools::Rectangle& rDamagedRegion) +{ + assert(m_pWidgetDraw); + assert(dynamic_cast(m_pWidgetDraw.get())); + assert(!rDamagedRegion.IsEmpty()); + + QImage* pImage = static_cast(m_pWidgetDraw.get())->getImage(); + QImage blit(*pImage); + blit.setDevicePixelRatio(1); + Qt5Painter aPainter(*this); + aPainter.drawImage(QPoint(rDamagedRegion.getX(), rDamagedRegion.getY()), blit); + aPainter.update(toQRect(rDamagedRegion)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_Controls.cxx b/vcl/qt5/Qt5Graphics_Controls.cxx new file mode 100644 index 000000000..dce9c1687 --- /dev/null +++ b/vcl/qt5/Qt5Graphics_Controls.cxx @@ -0,0 +1,1111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/** + 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, ...) +*/ +static QStyle::State vclStateValue2StateFlag(ControlState nControlState, + const ImplControlValue& aValue) +{ + QStyle::State nState + = ((nControlState & ControlState::ENABLED) ? QStyle::State_Enabled : QStyle::State_None) + | ((nControlState & ControlState::FOCUSED) ? QStyle::State_HasFocus : QStyle::State_None) + | ((nControlState & ControlState::PRESSED) ? QStyle::State_Sunken : QStyle::State_None) + | ((nControlState & ControlState::SELECTED) ? QStyle::State_Selected : QStyle::State_None) + | ((nControlState & ControlState::ROLLOVER) ? QStyle::State_MouseOver + : 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; +} + +Qt5Graphics_Controls::Qt5Graphics_Controls(const Qt5GraphicsBase& rGraphics) + : m_rGraphics(rGraphics) +{ +} + +bool Qt5Graphics_Controls::isNativeControlSupported(ControlType type, ControlPart part) +{ + switch (type) + { + case ControlType::Tooltip: + case ControlType::Progress: + case ControlType::ListNode: + return (part == ControlPart::Entire); + + case ControlType::Radiobutton: + case ControlType::Checkbox: + return (part == ControlPart::Entire) || (part == ControlPart::Focus); + case ControlType::Pushbutton: + return (part == ControlPart::Entire); + + case ControlType::ListHeader: + return (part == ControlPart::Button); + + case ControlType::Menubar: + case ControlType::MenuPopup: + case ControlType::Editbox: + case ControlType::MultilineEditbox: + case ControlType::Combobox: + case ControlType::Toolbar: + case ControlType::Frame: + case ControlType::Scrollbar: + case ControlType::WindowBackground: + case ControlType::Fixedline: + return true; + + case ControlType::Listbox: + return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); + + case ControlType::Spinbox: + return (part == ControlPart::Entire || part == ControlPart::HasBackgroundTexture); + + case ControlType::Slider: + return (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea); + + case ControlType::TabItem: + case ControlType::TabPane: + return ((part == ControlPart::Entire) || part == ControlPart::TabPaneWithHeader); + + default: + break; + } + + return false; +} + +inline int Qt5Graphics_Controls::pixelMetric(QStyle::PixelMetric metric, const QStyleOption* option) +{ + return QApplication::style()->pixelMetric(metric, option); +} + +inline QSize Qt5Graphics_Controls::sizeFromContents(QStyle::ContentsType type, + const QStyleOption* option, + const QSize& contentsSize) +{ + return QApplication::style()->sizeFromContents(type, option, contentsSize); +} + +inline QRect Qt5Graphics_Controls::subControlRect(QStyle::ComplexControl control, + const QStyleOptionComplex* option, + QStyle::SubControl subControl) +{ + return QApplication::style()->subControlRect(control, option, subControl); +} + +inline QRect Qt5Graphics_Controls::subElementRect(QStyle::SubElement element, + const QStyleOption* option) +{ + return QApplication::style()->subElementRect(element, option); +} + +void Qt5Graphics_Controls::draw(QStyle::ControlElement element, QStyleOption* option, QImage* image, + QStyle::State const state, QRect rect) +{ + const QRect& targetRect = !rect.isNull() ? rect : image->rect(); + + option->state |= state; + option->rect = downscale(targetRect); + + QPainter painter(image); + QApplication::style()->drawControl(element, option, &painter); +} + +void Qt5Graphics_Controls::draw(QStyle::PrimitiveElement element, QStyleOption* option, + QImage* image, QStyle::State const state, QRect rect) +{ + const QRect& targetRect = !rect.isNull() ? rect : image->rect(); + + option->state |= state; + option->rect = downscale(targetRect); + + QPainter painter(image); + QApplication::style()->drawPrimitive(element, option, &painter); +} + +void Qt5Graphics_Controls::draw(QStyle::ComplexControl element, QStyleOptionComplex* option, + QImage* image, QStyle::State const state) +{ + const QRect& targetRect = image->rect(); + + option->state |= state; + option->rect = downscale(targetRect); + + QPainter painter(image); + QApplication::style()->drawComplexControl(element, option, &painter); +} + +void Qt5Graphics_Controls::drawFrame(QStyle::PrimitiveElement element, QImage* image, + QStyle::State const& state, bool bClip, + QStyle::PixelMetric eLineMetric) +{ + const int fw = pixelMetric(eLineMetric); + QStyleOptionFrame option; + option.frameShape = QFrame::StyledPanel; + option.state = QStyle::State_Sunken | state; + option.lineWidth = fw; + + QRect aRect = downscale(image->rect()); + option.rect = aRect; + + QPainter painter(image); + if (bClip) + painter.setClipRegion(QRegion(aRect).subtracted(aRect.adjusted(fw, fw, -fw, -fw))); + QApplication::style()->drawPrimitive(element, &option, &painter); +} + +void Qt5Graphics_Controls::fillQStyleOptionTab(const ImplControlValue& value, QStyleOptionTab& sot) +{ + const TabitemValue& rValue = static_cast(value); + if (rValue.isFirst()) + sot.position = rValue.isLast() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::Beginning; + else if (rValue.isLast()) + sot.position = rValue.isFirst() ? QStyleOptionTab::OnlyOneTab : QStyleOptionTab::End; + else + sot.position = QStyleOptionTab::Middle; +} + +void Qt5Graphics_Controls::fullQStyleOptionTabWidgetFrame(QStyleOptionTabWidgetFrame& option, + bool bDownscale) +{ + option.state = QStyle::State_Enabled; + option.rightCornerWidgetSize = QSize(0, 0); + option.leftCornerWidgetSize = QSize(0, 0); + int nLineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); + option.lineWidth = bDownscale ? std::max(1, downscale(nLineWidth, Round::Ceil)) : nLineWidth; + option.midLineWidth = 0; + option.shape = QTabBar::RoundedNorth; +} + +bool Qt5Graphics_Controls::drawNativeControl(ControlType type, ControlPart part, + const tools::Rectangle& rControlRegion, + ControlState nControlState, + const ImplControlValue& value, const OUString&, + const Color& /*rBackgroundColor*/) +{ + bool nativeSupport = isNativeControlSupported(type, part); + if (!nativeSupport) + { + assert(!nativeSupport && "drawNativeControl called without native support!"); + return false; + } + + if (m_lastPopupRect.isValid() + && (type != ControlType::MenuPopup || part != ControlPart::MenuItem)) + m_lastPopupRect = QRect(); + + bool returnVal = true; + + QRect widgetRect = toQRect(rControlRegion); + + //if no image, or resized, make a new image + if (!m_image || m_image->size() != widgetRect.size()) + { + m_image.reset(new QImage(widgetRect.width(), widgetRect.height(), + QImage::Format_ARGB32_Premultiplied)); + m_image->setDevicePixelRatio(m_rGraphics.devicePixelRatioF()); + } + + // Default image color - just once + switch (type) + { + case ControlType::MenuPopup: + if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) + { + // it is necessary to fill the background transparently first, as this + // is painted after menuitem highlight, otherwise there would be a grey area + m_image->fill(Qt::transparent); + break; + } + [[fallthrough]]; // QPalette::Window + case ControlType::Menubar: + case ControlType::WindowBackground: + m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); + break; + case ControlType::Tooltip: + m_image->fill(QApplication::palette().color(QPalette::ToolTipBase).rgb()); + break; + case ControlType::Scrollbar: + if ((part == ControlPart::DrawBackgroundVert) + || (part == ControlPart::DrawBackgroundHorz)) + { + m_image->fill(QApplication::palette().color(QPalette::Window).rgb()); + break; + } + [[fallthrough]]; // Qt::transparent + default: + m_image->fill(Qt::transparent); + break; + } + + if (type == ControlType::Pushbutton) + { + assert(part == ControlPart::Entire); + QStyleOptionButton option; + draw(QStyle::CE_PushButton, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Menubar) + { + if (part == ControlPart::MenuItem) + { + QStyleOptionMenuItem option; + option.state = vclStateValue2StateFlag(nControlState, value); + if ((nControlState & ControlState::ROLLOVER) + && QApplication::style()->styleHint(QStyle::SH_MenuBar_MouseTracking)) + option.state |= QStyle::State_Selected; + + if (nControlState + & ControlState::SELECTED) // Passing State_Sunken is currently not documented. + option.state |= QStyle::State_Sunken; // But some kinds of QStyle interpret it. + + draw(QStyle::CE_MenuBarItem, &option, m_image.get()); + } + else if (part == ControlPart::Entire) + { + QStyleOptionMenuItem option; + draw(QStyle::CE_MenuBarEmptyArea, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else + { + returnVal = false; + } + } + else if (type == ControlType::MenuPopup) + { + assert(part == ControlPart::MenuItem ? m_lastPopupRect.isValid() + : !m_lastPopupRect.isValid()); + if (part == ControlPart::MenuItem) + { + QStyleOptionMenuItem option; + draw(QStyle::CE_MenuItem, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + // HACK: LO core first paints the entire popup and only then it paints menu items, + // but QMenu::paintEvent() paints popup frame after all items. That means highlighted + // items here would paint the highlight over the frame border. Since calls to ControlPart::MenuItem + // are always preceded by calls to ControlPart::Entire, just remember the size for the whole + // popup (otherwise not possible to get here) and draw the border afterwards. + QRect framerect(m_lastPopupRect.topLeft() - widgetRect.topLeft(), + widgetRect.size().expandedTo(m_lastPopupRect.size())); + QStyleOptionFrame frame; + draw(QStyle::PE_FrameMenu, &frame, m_image.get(), + vclStateValue2StateFlag(nControlState, value), framerect); + } + else if (part == ControlPart::Separator) + { + QStyleOptionMenuItem option; + option.menuItemType = QStyleOptionMenuItem::Separator; + // Painting the whole menu item area results in different background + // with at least Plastique style, so clip only to the separator itself + // (QSize( 2, 2 ) is hardcoded in Qt) + option.rect = m_image->rect(); + QSize size = sizeFromContents(QStyle::CT_MenuItem, &option, QSize(2, 2)); + QRect rect = m_image->rect(); + QPoint center = rect.center(); + rect.setHeight(size.height()); + rect.moveCenter(center); + option.state |= vclStateValue2StateFlag(nControlState, value); + option.rect = rect; + + QPainter painter(m_image.get()); + // don't paint over popup frame border (like the hack above, but here it can be simpler) + const int fw = pixelMetric(QStyle::PM_MenuPanelWidth); + painter.setClipRect(rect.adjusted(fw, 0, -fw, 0)); + QApplication::style()->drawControl(QStyle::CE_MenuItem, &option, &painter); + } + else if (part == ControlPart::MenuItemCheckMark || part == ControlPart::MenuItemRadioMark) + { + QStyleOptionMenuItem option; + option.checkType = (part == ControlPart::MenuItemCheckMark) + ? QStyleOptionMenuItem::NonExclusive + : QStyleOptionMenuItem::Exclusive; + option.checked = bool(nControlState & ControlState::PRESSED); + // widgetRect is now the rectangle for the checkbox/radiobutton itself, but Qt + // paints the whole menu item, so translate position (and it'll be clipped); + // it is also necessary to fill the background transparently first, as this + // is painted after menuitem highlight, otherwise there would be a grey area + assert(value.getType() == ControlType::MenuPopup); + const MenupopupValue* menuVal = static_cast(&value); + QRect menuItemRect(toQRect(menuVal->maItemRect)); + QRect rect(menuItemRect.topLeft() - widgetRect.topLeft(), + widgetRect.size().expandedTo(menuItemRect.size())); + // checkboxes are always displayed next to images in menus, so are never centered + const int focus_size = pixelMetric(QStyle::PM_FocusFrameHMargin); + rect.moveTo(-focus_size, rect.y()); + draw(QStyle::CE_MenuItem, &option, m_image.get(), + vclStateValue2StateFlag(nControlState & ~ControlState::PRESSED, value), rect); + } + else if (part == ControlPart::Entire) + { + QStyleOptionMenuItem option; + option.state = vclStateValue2StateFlag(nControlState, value); + draw(QStyle::PE_PanelMenu, &option, m_image.get()); + // Try hard to get any frame! + QStyleOptionFrame frame; + draw(QStyle::PE_FrameMenu, &frame, m_image.get()); + draw(QStyle::PE_FrameWindow, &frame, m_image.get()); + m_lastPopupRect = widgetRect; + } + else + returnVal = false; + } + else if ((type == ControlType::Toolbar) && (part == ControlPart::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.get()); + } + else if ((type == ControlType::Toolbar) && (part == ControlPart::Entire)) + { + QStyleOptionToolBar option; + draw(QStyle::CE_ToolBar, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if ((type == ControlType::Toolbar) + && (part == ControlPart::ThumbVert || part == ControlPart::ThumbHorz)) + { + // reduce paint area only to the handle area + const int handleExtend = pixelMetric(QStyle::PM_ToolBarHandleExtent); + QStyleOption option; + QRect aRect = m_image->rect(); + if (part == ControlPart::ThumbVert) + { + aRect.setWidth(handleExtend); + option.state = QStyle::State_Horizontal; + } + else + aRect.setHeight(handleExtend); + draw(QStyle::PE_IndicatorToolBarHandle, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value), aRect); + } + else if (type == ControlType::Editbox || type == ControlType::MultilineEditbox) + { + drawFrame(QStyle::PE_FrameLineEdit, m_image.get(), + vclStateValue2StateFlag(nControlState, value), false); + } + else if (type == ControlType::Combobox) + { + QStyleOptionComboBox option; + option.editable = true; + draw(QStyle::CC_ComboBox, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Listbox) + { + QStyleOptionComboBox option; + option.editable = false; + switch (part) + { + case ControlPart::ListboxWindow: + drawFrame(QStyle::PE_Frame, m_image.get(), + vclStateValue2StateFlag(nControlState, value), true, + QStyle::PM_ComboBoxFrameWidth); + break; + case ControlPart::SubEdit: + draw(QStyle::CE_ComboBoxLabel, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + break; + case ControlPart::Entire: + draw(QStyle::CC_ComboBox, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + break; + case ControlPart::ButtonDown: + option.subControls = QStyle::SC_ComboBoxArrow; + draw(QStyle::CC_ComboBox, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + break; + default: + returnVal = false; + break; + } + } + else if (type == ControlType::ListNode) + { + QStyleOption option; + option.state = vclStateValue2StateFlag(nControlState, value); + option.state |= QStyle::State_Item | QStyle::State_Children; + + if (value.getTristateVal() == ButtonValue::On) + option.state |= QStyle::State_Open; + + draw(QStyle::PE_IndicatorBranch, &option, m_image.get()); + } + else if (type == ControlType::ListHeader) + { + QStyleOptionHeader option; + draw(QStyle::CE_HeaderSection, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Checkbox) + { + if (part == ControlPart::Entire) + { + QStyleOptionButton option; + // clear FOCUSED bit, focus is drawn separately + nControlState &= ~ControlState::FOCUSED; + draw(QStyle::CE_CheckBox, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (part == ControlPart::Focus) + { + QStyleOptionFocusRect option; + draw(QStyle::PE_FrameFocusRect, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + } + else if (type == ControlType::Scrollbar) + { + if ((part == ControlPart::DrawBackgroundVert) || (part == ControlPart::DrawBackgroundHorz)) + { + QStyleOptionSlider option; + assert(value.getType() == ControlType::Scrollbar); + const ScrollbarValue* sbVal = static_cast(&value); + + //if the scroll bar is active (aka not degenerate... allow for hover events) + if (sbVal->mnVisibleSize < sbVal->mnMax) + option.state = QStyle::State_MouseOver; + + bool horizontal = (part == ControlPart::DrawBackgroundHorz); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + + // If the scrollbar has a mnMin == 0 and mnMax == 0 then mnVisibleSize is set to -1?! + // I don't know if a negative mnVisibleSize makes any sense, so just handle this case + // without crashing LO with a SIGFPE in the Qt library. + const long nVisibleSize = (sbVal->mnMin == sbVal->mnMax) ? 0 : sbVal->mnVisibleSize; + + option.minimum = sbVal->mnMin; + option.maximum = sbVal->mnMax - nVisibleSize; + option.maximum = qMax(option.maximum, option.minimum); // bnc#619772 + option.sliderValue = sbVal->mnCur; + option.sliderPosition = sbVal->mnCur; + option.pageStep = nVisibleSize; + if (part == ControlPart::DrawBackgroundHorz) + option.upsideDown + = (QGuiApplication::isRightToLeft() + && sbVal->maButton1Rect.Left() < sbVal->maButton2Rect.Left()) + || (QGuiApplication::isLeftToRight() + && sbVal->maButton1Rect.Left() > sbVal->maButton2Rect.Left()); + + //setup the active control... always the slider + if (sbVal->mnThumbState & ControlState::ROLLOVER) + option.activeSubControls = QStyle::SC_ScrollBarSlider; + + draw(QStyle::CC_ScrollBar, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else + { + returnVal = false; + } + } + else if (type == ControlType::Spinbox) + { + QStyleOptionSpinBox option; + option.frame = true; + + // determine active control + if (value.getType() == ControlType::SpinButtons) + { + const SpinbuttonValue* pSpinVal = static_cast(&value); + if (pSpinVal->mnUpperState & ControlState::PRESSED) + option.activeSubControls |= QStyle::SC_SpinBoxUp; + if (pSpinVal->mnLowerState & ControlState::PRESSED) + option.activeSubControls |= QStyle::SC_SpinBoxDown; + if (pSpinVal->mnUpperState & ControlState::ENABLED) + option.stepEnabled |= QAbstractSpinBox::StepUpEnabled; + if (pSpinVal->mnLowerState & ControlState::ENABLED) + option.stepEnabled |= QAbstractSpinBox::StepDownEnabled; + if (pSpinVal->mnUpperState & ControlState::ROLLOVER) + option.state = QStyle::State_MouseOver; + if (pSpinVal->mnLowerState & ControlState::ROLLOVER) + option.state = QStyle::State_MouseOver; + } + + draw(QStyle::CC_SpinBox, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Radiobutton) + { + if (part == ControlPart::Entire) + { + QStyleOptionButton option; + // clear FOCUSED bit, focus is drawn separately + nControlState &= ~ControlState::FOCUSED; + draw(QStyle::CE_RadioButton, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (part == ControlPart::Focus) + { + QStyleOptionFocusRect option; + draw(QStyle::PE_FrameFocusRect, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + } + else if (type == ControlType::Tooltip) + { + QStyleOption option; + draw(QStyle::PE_PanelTipLabel, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::Frame) + { + drawFrame(QStyle::PE_Frame, m_image.get(), vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::WindowBackground) + { + // Nothing to do - see "Default image color" switch ^^ + } + else if (type == ControlType::Fixedline) + { + QStyleOptionMenuItem option; + option.menuItemType = QStyleOptionMenuItem::Separator; + option.state = vclStateValue2StateFlag(nControlState, value); + option.state |= QStyle::State_Item; + + draw(QStyle::CE_MenuItem, &option, m_image.get()); + } + else if (type == ControlType::Slider + && (part == ControlPart::TrackHorzArea || part == ControlPart::TrackVertArea)) + { + assert(value.getType() == ControlType::Slider); + const SliderValue* slVal = static_cast(&value); + QStyleOptionSlider option; + + option.state = vclStateValue2StateFlag(nControlState, value); + option.maximum = slVal->mnMax; + option.minimum = slVal->mnMin; + option.sliderPosition = option.sliderValue = slVal->mnCur; + bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + + draw(QStyle::CC_Slider, &option, m_image.get()); + } + else if (type == ControlType::Progress && part == ControlPart::Entire) + { + SAL_WNODEPRECATED_DECLARATIONS_PUSH + QStyleOptionProgressBarV2 option; + SAL_WNODEPRECATED_DECLARATIONS_POP + option.minimum = 0; + option.maximum = widgetRect.width(); + option.progress = value.getNumericVal(); + + draw(QStyle::CE_ProgressBar, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::TabItem && part == ControlPart::Entire) + { + QStyleOptionTab sot; + fillQStyleOptionTab(value, sot); + draw(QStyle::CE_TabBarTabShape, &sot, m_image.get(), + vclStateValue2StateFlag(nControlState, value)); + } + else if (type == ControlType::TabPane && part == ControlPart::Entire) + { + const TabPaneValue& rValue = static_cast(value); + + // get the overlap size for the tabs, so they will overlap the frame + QStyleOptionTab tabOverlap; + tabOverlap.shape = QTabBar::RoundedNorth; + TabPaneValue::m_nOverlap = pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap); + + QStyleOptionTabWidgetFrame option; + fullQStyleOptionTabWidgetFrame(option, false); + option.tabBarRect = toQRect(rValue.m_aTabHeaderRect); + option.selectedTabRect + = rValue.m_aSelectedTabRect.IsEmpty() ? QRect() : toQRect(rValue.m_aSelectedTabRect); + option.tabBarSize = toQSize(rValue.m_aTabHeaderRect.GetSize()); + option.rect = m_image->rect(); + QRect aRect = subElementRect(QStyle::SE_TabWidgetTabPane, &option); + draw(QStyle::PE_FrameTabWidget, &option, m_image.get(), + vclStateValue2StateFlag(nControlState, value), aRect); + } + else + { + returnVal = false; + } + + return returnVal; +} + +bool Qt5Graphics_Controls::getNativeControlRegion(ControlType type, ControlPart part, + const tools::Rectangle& controlRegion, + ControlState controlState, + const ImplControlValue& val, const OUString&, + tools::Rectangle& nativeBoundingRegion, + tools::Rectangle& nativeContentRegion) +{ + bool retVal = false; + + QRect boundingRect = toQRect(controlRegion); + QRect contentRect = boundingRect; + QStyleOptionComplex styleOption; + + switch (type) + { + // Metrics of the push button + case ControlType::Pushbutton: + if (part == ControlPart::Entire) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + if (controlState & ControlState::DEFAULT) + { + int size = upscale(pixelMetric(QStyle::PM_ButtonDefaultIndicator, &styleOption), + Round::Ceil); + boundingRect.adjust(-size, -size, size, size); + retVal = true; + } + } + break; + case ControlType::Editbox: + case ControlType::MultilineEditbox: + { + // we have to get stable borders, otherwise layout loops. + // so we simply only scale the detected borders. + QStyleOptionFrame fo; + fo.frameShape = QFrame::StyledPanel; + fo.state = QStyle::State_Sunken; + fo.lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth); + fo.rect = downscale(contentRect); + fo.rect.setSize(sizeFromContents(QStyle::CT_LineEdit, &fo, fo.rect.size())); + QRect aSubRect = subElementRect(QStyle::SE_LineEditContents, &fo); + + // VCL tests borders with small defaults before layout, where Qt returns no sub-rect, + // so this gets us at least some frame. + int nLine = upscale(fo.lineWidth, Round::Ceil); + int nLeft = qMin(-nLine, upscale(fo.rect.left() - aSubRect.left(), Round::Floor)); + int nTop = qMin(-nLine, upscale(fo.rect.top() - aSubRect.top(), Round::Floor)); + int nRight = qMax(nLine, upscale(fo.rect.right() - aSubRect.right(), Round::Ceil)); + int nBottom = qMax(nLine, upscale(fo.rect.bottom() - aSubRect.bottom(), Round::Ceil)); + boundingRect.adjust(nLeft, nTop, nRight, nBottom); + retVal = true; + break; + } + case ControlType::Checkbox: + if (part == ControlPart::Entire) + { + styleOption.state = vclStateValue2StateFlag(controlState, val); + + int nWidth = pixelMetric(QStyle::PM_IndicatorWidth, &styleOption); + int nHeight = pixelMetric(QStyle::PM_IndicatorHeight, &styleOption); + contentRect.setSize(upscale(QSize(nWidth, nHeight), Round::Ceil)); + + int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); + int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); + contentRect.adjust(0, 0, 2 * upscale(nHMargin, Round::Ceil), + 2 * upscale(nVMargin, Round::Ceil)); + + boundingRect = contentRect; + retVal = true; + } + break; + case ControlType::Combobox: + case ControlType::Listbox: + { + QStyleOptionComboBox cbo; + + cbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); + cbo.state = vclStateValue2StateFlag(controlState, val); + + switch (part) + { + case ControlPart::Entire: + { + // find out the minimum size that should be used + // assume contents is a text line + QSize aContentSize = downscale(contentRect.size(), Round::Ceil); + aContentSize.setHeight(QApplication::fontMetrics().height()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_ComboBox, &cbo, aContentSize), Round::Ceil); + if (aMinSize.height() > contentRect.height()) + contentRect.setHeight(aMinSize.height()); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlPart::ButtonDown: + { + contentRect = upscale( + subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxArrow)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + } + case ControlPart::SubEdit: + { + contentRect = upscale( + subControlRect(QStyle::CC_ComboBox, &cbo, QStyle::SC_ComboBoxEditField)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + } + default: + break; + } + break; + } + case ControlType::Spinbox: + { + QStyleOptionSpinBox sbo; + sbo.frame = true; + + sbo.rect = downscale(QRect(0, 0, contentRect.width(), contentRect.height())); + sbo.state = vclStateValue2StateFlag(controlState, val); + + switch (part) + { + case ControlPart::Entire: + { + QSize aContentSize = downscale(contentRect.size(), Round::Ceil); + aContentSize.setHeight(QApplication::fontMetrics().height()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_SpinBox, &sbo, aContentSize), Round::Ceil); + if (aMinSize.height() > contentRect.height()) + contentRect.setHeight(aMinSize.height()); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlPart::ButtonUp: + contentRect + = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxUp)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + case ControlPart::ButtonDown: + contentRect + = upscale(subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxDown)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + case ControlPart::SubEdit: + contentRect = upscale( + subControlRect(QStyle::CC_SpinBox, &sbo, QStyle::SC_SpinBoxEditField)); + contentRect.translate(boundingRect.left(), boundingRect.top()); + retVal = true; + break; + default: + break; + } + break; + } + case ControlType::MenuPopup: + { + int h, w; + switch (part) + { + case ControlPart::MenuItemCheckMark: + h = upscale(pixelMetric(QStyle::PM_IndicatorHeight), Round::Floor); + w = upscale(pixelMetric(QStyle::PM_IndicatorWidth), Round::Floor); + retVal = true; + break; + case ControlPart::MenuItemRadioMark: + h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Floor); + w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Floor); + retVal = true; + break; + default: + break; + } + if (retVal) + { + contentRect = QRect(0, 0, w, h); + boundingRect = contentRect; + } + break; + } + case ControlType::Frame: + { + if (part == ControlPart::Border) + { + auto nStyle = static_cast(val.getNumericVal() & 0xFFF0); + if (nStyle & DrawFrameFlags::NoDraw) + { + int nFrameWidth + = upscale(pixelMetric(QStyle::PM_DefaultFrameWidth), Round::Ceil); + contentRect.adjust(nFrameWidth, nFrameWidth, -nFrameWidth, -nFrameWidth); + } + retVal = true; + } + break; + } + case ControlType::Radiobutton: + { + const int h = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorHeight), Round::Ceil); + const int w = upscale(pixelMetric(QStyle::PM_ExclusiveIndicatorWidth), Round::Ceil); + + contentRect = QRect(boundingRect.left(), boundingRect.top(), w, h); + int nHMargin = pixelMetric(QStyle::PM_FocusFrameHMargin, &styleOption); + int nVMargin = pixelMetric(QStyle::PM_FocusFrameVMargin, &styleOption); + contentRect.adjust(0, 0, upscale(2 * nHMargin, Round::Ceil), + upscale(2 * nVMargin, Round::Ceil)); + boundingRect = contentRect; + + retVal = true; + break; + } + case ControlType::Slider: + { + const int w = upscale(pixelMetric(QStyle::PM_SliderLength), Round::Ceil); + if (part == ControlPart::ThumbHorz) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), w, boundingRect.height()); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::ThumbVert) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), w); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::Toolbar: + { + const int nWorH = upscale(pixelMetric(QStyle::PM_ToolBarHandleExtent), Round::Ceil); + if (part == ControlPart::ThumbHorz) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), boundingRect.width(), nWorH); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::ThumbVert) + { + contentRect + = QRect(boundingRect.left(), boundingRect.top(), nWorH, boundingRect.height()); + boundingRect = contentRect; + retVal = true; + } + else if (part == ControlPart::Button) + { + QStyleOptionToolButton option; + option.arrowType = Qt::NoArrow; + option.features = QStyleOptionToolButton::None; + option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); + contentRect = upscale( + subControlRect(QStyle::CC_ToolButton, &option, QStyle::SC_ToolButton)); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::Scrollbar: + { + // core can't handle 3-button scrollbars well, so we fix that in hitTestNativeControl(), + // for the rest also provide the track area (i.e. area not taken by buttons) + if (part == ControlPart::TrackVertArea || part == ControlPart::TrackHorzArea) + { + QStyleOptionSlider option; + bool horizontal = (part == ControlPart::TrackHorzArea); //horizontal or vertical + option.orientation = horizontal ? Qt::Horizontal : Qt::Vertical; + if (horizontal) + option.state |= QStyle::State_Horizontal; + // getNativeControlRegion usually gets ImplControlValue as 'val' (i.e. not the proper + // subclass), so use random sensible values (doesn't matter anyway, as the wanted + // geometry here depends only on button sizes) + option.maximum = 10; + option.minimum = 0; + option.sliderPosition = option.sliderValue = 4; + option.pageStep = 2; + // Adjust coordinates to make the widget appear to be at (0,0), i.e. make + // widget and screen coordinates the same. QStyle functions should use screen + // coordinates but at least QPlastiqueStyle::subControlRect() is buggy + // and sometimes uses widget coordinates. + option.rect = downscale(QRect({ 0, 0 }, contentRect.size())); + contentRect = upscale( + subControlRect(QStyle::CC_ScrollBar, &option, QStyle::SC_ScrollBarGroove)); + contentRect.translate(boundingRect.left() + - (contentRect.width() - boundingRect.width()), + boundingRect.top()); + boundingRect = contentRect; + retVal = true; + } + break; + } + case ControlType::TabItem: + { + QStyleOptionTab sot; + fillQStyleOptionTab(val, sot); + QSize aMinSize = upscale(sizeFromContents(QStyle::CT_TabBarTab, &sot, + downscale(contentRect.size(), Round::Ceil)), + Round::Ceil); + contentRect.setSize(aMinSize); + boundingRect = contentRect; + retVal = true; + break; + } + case ControlType::TabPane: + { + const TabPaneValue& rValue = static_cast(val); + QStyleOptionTabWidgetFrame sotwf; + fullQStyleOptionTabWidgetFrame(sotwf, true); + QSize contentSize( + std::max(rValue.m_aTabHeaderRect.GetWidth(), controlRegion.GetWidth()), + rValue.m_aTabHeaderRect.GetHeight() + controlRegion.GetHeight()); + QSize aMinSize = upscale( + sizeFromContents(QStyle::CT_TabWidget, &sotwf, downscale(contentSize, Round::Ceil)), + Round::Ceil); + contentRect.setSize(aMinSize); + boundingRect = contentRect; + retVal = true; + break; + } + default: + break; + } + if (retVal) + { + nativeBoundingRegion = toRectangle(boundingRect); + nativeContentRegion = toRectangle(contentRect); + } + + return retVal; +} + +/** 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 Qt5Graphics_Controls::hitTestNativeControl(ControlType nType, ControlPart nPart, + const tools::Rectangle& rControlRegion, + const Point& rPos, bool& rIsInside) +{ + if (nType == ControlType::Scrollbar) + { + if (nPart != ControlPart::ButtonUp && nPart != ControlPart::ButtonDown + && nPart != ControlPart::ButtonLeft && nPart != ControlPart::ButtonRight) + { // we adjust only for buttons (because some scrollbars have 3 buttons, + // and LO core doesn't handle such scrollbars well) + return false; + } + rIsInside = false; + bool bHorizontal = (nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight); + QRect rect = toQRect(rControlRegion); + QPoint pos(rPos.X(), rPos.Y()); + // Adjust coordinates to make the widget appear to be at (0,0), i.e. make + // widget and screen coordinates the same. QStyle functions should use screen + // coordinates but at least QPlastiqueStyle::subControlRect() is buggy + // and sometimes uses widget coordinates. + pos -= rect.topLeft(); + rect.moveTo(0, 0); + QStyleOptionSlider options; + options.orientation = bHorizontal ? Qt::Horizontal : Qt::Vertical; + if (bHorizontal) + options.state |= QStyle::State_Horizontal; + options.rect = rect; + // some random sensible values, since we call this code only for scrollbar buttons, + // the slider position does not exactly matter + options.maximum = 10; + options.minimum = 0; + options.sliderPosition = options.sliderValue = 4; + options.pageStep = 2; + QStyle::SubControl control + = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &options, pos); + if (nPart == ControlPart::ButtonUp || nPart == ControlPart::ButtonLeft) + rIsInside = (control == QStyle::SC_ScrollBarSubLine); + else // DOWN, RIGHT + rIsInside = (control == QStyle::SC_ScrollBarAddLine); + return true; + } + return false; +} + +inline int Qt5Graphics_Controls::downscale(int size, Round eRound) +{ + return static_cast(eRound == Round::Ceil ? ceil(size / m_rGraphics.devicePixelRatioF()) + : floor(size / m_rGraphics.devicePixelRatioF())); +} + +inline int Qt5Graphics_Controls::upscale(int size, Round eRound) +{ + return static_cast(eRound == Round::Ceil ? ceil(size * m_rGraphics.devicePixelRatioF()) + : floor(size * m_rGraphics.devicePixelRatioF())); +} + +inline QRect Qt5Graphics_Controls::downscale(const QRect& rect) +{ + return QRect(downscale(rect.x(), Round::Floor), downscale(rect.y(), Round::Floor), + downscale(rect.width(), Round::Ceil), downscale(rect.height(), Round::Ceil)); +} + +inline QRect Qt5Graphics_Controls::upscale(const QRect& rect) +{ + return QRect(upscale(rect.x(), Round::Floor), upscale(rect.y(), Round::Floor), + upscale(rect.width(), Round::Ceil), upscale(rect.height(), Round::Ceil)); +} + +inline QSize Qt5Graphics_Controls::downscale(const QSize& size, Round eRound) +{ + return QSize(downscale(size.width(), eRound), downscale(size.height(), eRound)); +} + +inline QSize Qt5Graphics_Controls::upscale(const QSize& size, Round eRound) +{ + return QSize(upscale(size.width(), eRound), upscale(size.height(), eRound)); +} + +inline QPoint Qt5Graphics_Controls::upscale(const QPoint& point, Round eRound) +{ + return QPoint(upscale(point.x(), eRound), upscale(point.y(), eRound)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx new file mode 100644 index 000000000..cfebca7c6 --- /dev/null +++ b/vcl/qt5/Qt5Graphics_GDI.cxx @@ -0,0 +1,712 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +static const basegfx::B2DPoint aHalfPointOfs(0.5, 0.5); + +static void AddPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolygon& rPolygon, + bool bClosePath, bool bPixelSnap, bool bLineDraw) +{ + const int nPointCount = rPolygon.count(); + // short circuit if there is nothing to do + if (nPointCount == 0) + return; + + 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 + rPath.moveTo(aPoint.getX(), aPoint.getY()); + continue; + } + + bool bPendingCurve = false; + if (bHasCurves) + { + bPendingCurve = rPolygon.isNextControlPointUsed(nPrevIdx); + bPendingCurve |= rPolygon.isPrevControlPointUsed(nClosedIdx); + } + + if (!bPendingCurve) // line segment + rPath.lineTo(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; + } + rPath.cubicTo(aCP1.getX(), aCP1.getY(), aCP2.getX(), aCP2.getY(), aPoint.getX(), + aPoint.getY()); + } + } + + if (bClosePath) + rPath.closeSubpath(); +} + +static bool AddPolyPolygonToPath(QPainterPath& rPath, const basegfx::B2DPolyPolygon& rPolyPoly, + bool bPixelSnap, bool bLineDraw) +{ + if (rPolyPoly.count() == 0) + return false; + for (auto const& rPolygon : rPolyPoly) + { + AddPolygonToPath(rPath, rPolygon, true, bPixelSnap, bLineDraw); + } + return true; +} + +bool Qt5Graphics::setClipRegion(const vcl::Region& rRegion) +{ + if (rRegion.IsRectangle()) + { + m_aClipRegion = toQRect(rRegion.GetBoundRect()); + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } + } + else if (!rRegion.HasPolyPolygonOrB2DPolyPolygon()) + { + QRegion aQRegion; + RectangleVector aRectangles; + rRegion.GetRegionRectangles(aRectangles); + for (const auto& rRect : aRectangles) + aQRegion += toQRect(rRect); + m_aClipRegion = aQRegion; + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } + } + else + { + QPainterPath aPath; + const basegfx::B2DPolyPolygon aPolyClip(rRegion.GetAsB2DPolyPolygon()); + AddPolyPolygonToPath(aPath, aPolyClip, !getAntiAliasB2DDraw(), false); + m_aClipPath.swap(aPath); + if (!m_aClipRegion.isEmpty()) + { + QRegion aRegion; + m_aClipRegion.swap(aRegion); + } + } + return true; +} + +void Qt5Graphics::ResetClipRegion() +{ + if (m_pQImage) + m_aClipRegion = QRegion(m_pQImage->rect()); + else + m_aClipRegion = QRegion(); + if (!m_aClipPath.isEmpty()) + { + QPainterPath aPath; + m_aClipPath.swap(aPath); + } +} + +void Qt5Graphics::drawPixel(long nX, long nY) +{ + Qt5Painter aPainter(*this); + aPainter.drawPoint(nX, nY); + aPainter.update(nX, nY, 1, 1); +} + +void Qt5Graphics::drawPixel(long nX, long nY, Color nColor) +{ + Qt5Painter aPainter(*this); + aPainter.setPen(toQColor(nColor)); + aPainter.setPen(Qt::SolidLine); + aPainter.drawPoint(nX, nY); + aPainter.update(nX, nY, 1, 1); +} + +void Qt5Graphics::drawLine(long nX1, long nY1, long nX2, long nY2) +{ + Qt5Painter aPainter(*this); + aPainter.drawLine(nX1, nY1, nX2, nY2); + + long tmp; + if (nX1 > nX2) + { + tmp = nX1; + nX1 = nX2; + nX2 = tmp; + } + if (nY1 > nY2) + { + tmp = nY1; + nY1 = nY2; + nY2 = tmp; + } + aPainter.update(nX1, nY1, nX2 - nX1 + 1, nY2 - nY1 + 1); +} + +void Qt5Graphics::drawRect(long nX, long nY, long nWidth, long nHeight) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return; + + Qt5Painter aPainter(*this, true); + if (SALCOLOR_NONE != m_aFillColor) + aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); + if (SALCOLOR_NONE != m_aLineColor) + aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); + aPainter.update(nX, nY, nWidth, nHeight); +} + +void Qt5Graphics::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + if (0 == nPoints) + return; + + Qt5Painter aPainter(*this); + QPoint* pPoints = new QPoint[nPoints]; + QPoint aTopLeft(pPtAry->mnX, pPtAry->mnY); + QPoint aBottomRight = aTopLeft; + for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) + { + pPoints[i] = QPoint(pPtAry->mnX, pPtAry->mnY); + if (pPtAry->mnX < aTopLeft.x()) + aTopLeft.setX(pPtAry->mnX); + if (pPtAry->mnY < aTopLeft.y()) + aTopLeft.setY(pPtAry->mnY); + if (pPtAry->mnX > aBottomRight.x()) + aBottomRight.setX(pPtAry->mnX); + if (pPtAry->mnY > aBottomRight.y()) + aBottomRight.setY(pPtAry->mnY); + } + aPainter.drawPolyline(pPoints, nPoints); + delete[] pPoints; + aPainter.update(QRect(aTopLeft, aBottomRight)); +} + +void Qt5Graphics::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + Qt5Painter aPainter(*this, true); + QPolygon aPolygon(nPoints); + for (sal_uInt32 i = 0; i < nPoints; ++i, ++pPtAry) + aPolygon.setPoint(i, pPtAry->mnX, pPtAry->mnY); + aPainter.drawPolygon(aPolygon); + aPainter.update(aPolygon.boundingRect()); +} + +void Qt5Graphics::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoints, + PCONSTSALPOINT* ppPtAry) +{ + // ignore invisible polygons + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return; + + QPainterPath aPath; + for (sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++) + { + const sal_uInt32 nPoints = pPoints[nPoly]; + if (nPoints > 1) + { + const SalPoint* pPtAry = ppPtAry[nPoly]; + aPath.moveTo(pPtAry->mnX, pPtAry->mnY); + pPtAry++; + for (sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++) + aPath.lineTo(pPtAry->mnX, pPtAry->mnY); + aPath.closeSubpath(); + } + } + + Qt5Painter aPainter(*this, true); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); +} + +bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) +{ + // ignore invisible polygons + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return true; + if ((fTransparency >= 1.0) || (fTransparency < 0)) + return true; + + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + QPainterPath aPath; + // ignore empty polygons + if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAliasB2DDraw(), + m_aLineColor != SALCOLOR_NONE)) + return true; + + Qt5Painter aPainter(*this, true, 255 * (1.0 - fTransparency)); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); + return true; +} + +bool Qt5Graphics::drawPolyLineBezier(sal_uInt32 /*nPoints*/, const SalPoint* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/) +{ + return false; +} + +bool Qt5Graphics::drawPolygonBezier(sal_uInt32 /*nPoints*/, const SalPoint* /*pPtAry*/, + const PolyFlags* /*pFlgAry*/) +{ + return false; +} + +bool Qt5Graphics::drawPolyPolygonBezier(sal_uInt32 /*nPoly*/, const sal_uInt32* /*pPoints*/, + const SalPoint* const* /*pPtAry*/, + const PolyFlags* const* /*pFlgAry*/) +{ + return false; +} + +bool Qt5Graphics::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, + const std::vector* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, bool bPixelSnapHairline) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + { + return true; + } + + // MM01 check done for simple reasons + if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength( + nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + assert(!bStrokeUsed || (bStrokeUsed && pStroke)); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if (bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing(rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } + + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline + aPolyPolygonLine.transform(rObjectToDevice); + if (bPixelSnapHairline) + { + aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); + } + + // tdf#124848 get correct LineWidth in discrete coordinates, + if (fLineWidth == 0) // hairline + fLineWidth = 1.0; + else // Adjust line width for object-to-device scale. + fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); + + // setup poly-polygon path + QPainterPath aPath; + + // MM01 todo - I assume that this is OKAY to be done in one run for Qt5, + // but this NEEDS to be checked/verified + for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + AddPolygonToPath(aPath, aPolyLine, aPolyLine.isClosed(), !getAntiAliasB2DDraw(), true); + } + + Qt5Painter aPainter(*this, false, 255 * (1.0 - fTransparency)); + + // setup line attributes + QPen aPen = aPainter.pen(); + aPen.setWidth(fLineWidth); + + switch (eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + aPen.setJoinStyle(Qt::BevelJoin); + break; + case basegfx::B2DLineJoin::Round: + aPen.setJoinStyle(Qt::RoundJoin); + break; + case basegfx::B2DLineJoin::NONE: + case basegfx::B2DLineJoin::Miter: + aPen.setMiterLimit(1.0 / sin(fMiterMinimumAngle / 2.0)); + aPen.setJoinStyle(Qt::MiterJoin); + break; + } + + switch (eLineCap) + { + default: // css::drawing::LineCap_BUTT: + aPen.setCapStyle(Qt::FlatCap); + break; + case css::drawing::LineCap_ROUND: + aPen.setCapStyle(Qt::RoundCap); + break; + case css::drawing::LineCap_SQUARE: + aPen.setCapStyle(Qt::SquareCap); + break; + } + + aPainter.setPen(aPen); + aPainter.drawPath(aPath); + aPainter.update(aPath.boundingRect()); + return true; +} + +bool Qt5Graphics::drawGradient(const tools::PolyPolygon&, const Gradient&) { return false; } + +void Qt5Graphics::drawScaledImage(const SalTwoRect& rPosAry, const QImage& rImage) +{ + Qt5Painter aPainter(*this); + QRect aSrcRect(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + QRect aDestRect(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + aPainter.drawImage(aDestRect, rImage, aSrcRect); + aPainter.update(aDestRect); +} + +void Qt5Graphics::copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool /*bWindowInvalidate*/) +{ + if (nDestX == nSrcX && nDestY == nSrcY) + return; + + SalTwoRect aTR(nSrcX, nSrcY, nSrcWidth, nSrcHeight, nDestX, nDestY, nSrcWidth, nSrcHeight); + copyBits(aTR, this); +} + +void Qt5Graphics::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + QImage aImage, *pImage; + SalTwoRect aPosAry = rPosAry; + if (!pSrcGraphics || this == pSrcGraphics) + { + pImage = m_pQImage; + aImage + = pImage->copy(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + pImage = &aImage; + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + } + else + pImage = static_cast(pSrcGraphics)->m_pQImage; + + drawScaledImage(aPosAry, *pImage); +} + +void Qt5Graphics::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + Qt5Bitmap aRGBABitmap; + if (rSalBitmap.GetBitCount() == 4) + aRGBABitmap.Create(rSalBitmap, 32); + const QImage* pImage = (rSalBitmap.GetBitCount() != 4) + ? static_cast(&rSalBitmap)->GetQImage() + : aRGBABitmap.GetQImage(); + assert(pImage); + + drawScaledImage(rPosAry, *pImage); +} + +void Qt5Graphics::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, + const SalBitmap& /*rTransparentBitmap*/) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); + assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); +} + +void Qt5Graphics::drawMask(const SalTwoRect& rPosAry, const SalBitmap& /*rSalBitmap*/, + Color /*nMaskColor*/) +{ + if (rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0) + return; + + assert(rPosAry.mnSrcWidth == rPosAry.mnDestWidth); + assert(rPosAry.mnSrcHeight == rPosAry.mnDestHeight); +} + +std::shared_ptr Qt5Graphics::getBitmap(long nX, long nY, long nWidth, long nHeight) +{ + return std::make_shared(m_pQImage->copy(nX, nY, nWidth, nHeight)); +} + +Color Qt5Graphics::getPixel(long nX, long nY) { return m_pQImage->pixel(nX, nY); } + +void Qt5Graphics::invert(long nX, long nY, long nWidth, long nHeight, SalInvert nFlags) +{ + Qt5Painter aPainter(*this); + if (SalInvert::N50 & nFlags) + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + QBrush aBrush(Qt::white, Qt::Dense4Pattern); + aPainter.fillRect(nX, nY, nWidth, nHeight, aBrush); + } + else + { + if (SalInvert::TrackFrame & nFlags) + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + QPen aPen(Qt::white); + aPen.setStyle(Qt::DotLine); + aPainter.setPen(aPen); + aPainter.drawRect(nX, nY, nWidth, nHeight); + } + else + { + aPainter.setCompositionMode(QPainter::RasterOp_SourceXorDestination); + aPainter.fillRect(nX, nY, nWidth, nHeight, Qt::white); + } + } + aPainter.update(nX, nY, nWidth, nHeight); +} + +void Qt5Graphics::invert(sal_uInt32 /*nPoints*/, const SalPoint* /*pPtAry*/, SalInvert /*nFlags*/) +{ +} + +bool Qt5Graphics::drawEPS(long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, + void* /*pPtr*/, sal_uInt32 /*nSize*/) +{ + return false; +} + +bool Qt5Graphics::blendBitmap(const SalTwoRect&, const SalBitmap& /*rBitmap*/) { return false; } + +bool Qt5Graphics::blendAlphaBitmap(const SalTwoRect&, const SalBitmap& /*rSrcBitmap*/, + const SalBitmap& /*rMaskBitmap*/, + const SalBitmap& /*rAlphaBitmap*/) +{ + return false; +} + +static bool getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap, + QImage& rAlphaImage) +{ + if (rAlphaBitmap.GetBitCount() != 8 && rAlphaBitmap.GetBitCount() != 1) + { + SAL_WARN("vcl.gdi", "unsupported alpha depth case: " << rAlphaBitmap.GetBitCount()); + return false; + } + + Qt5Bitmap aRGBABitmap; + if (rSourceBitmap.GetBitCount() == 4) + aRGBABitmap.Create(rSourceBitmap, 32); + const QImage* pBitmap = (rSourceBitmap.GetBitCount() != 4) + ? static_cast(&rSourceBitmap)->GetQImage() + : aRGBABitmap.GetQImage(); + const QImage* pAlpha = static_cast(&rAlphaBitmap)->GetQImage(); + rAlphaImage = pBitmap->convertToFormat(Qt5_DefaultFormat32); + + if (rAlphaBitmap.GetBitCount() == 8) + { + for (int y = 0; y < rAlphaImage.height(); ++y) + { + uchar* image_line = rAlphaImage.scanLine(y); + const uchar* alpha_line = pAlpha->scanLine(y); + for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) + image_line[3] = 255 - alpha_line[x]; + } + } + else + { + for (int y = 0; y < rAlphaImage.height(); ++y) + { + uchar* image_line = rAlphaImage.scanLine(y); + const uchar* alpha_line = pAlpha->scanLine(y); + for (int x = 0; x < rAlphaImage.width(); ++x, image_line += 4) + { + if (x && !(x % 8)) + ++alpha_line; + if (0 != (*alpha_line & (1 << (7 - x % 8)))) + image_line[3] = 0; + } + } + } + + return true; +} + +bool Qt5Graphics::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) +{ + QImage aImage; + if (!getAlphaImage(rSourceBitmap, rAlphaBitmap, aImage)) + return false; + drawScaledImage(rPosAry, aImage); + return true; +} + +bool Qt5Graphics::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + QImage aImage; + if (pAlphaBitmap && !getAlphaImage(rSourceBitmap, *pAlphaBitmap, aImage)) + return false; + else + { + Qt5Bitmap aRGBABitmap; + if (rSourceBitmap.GetBitCount() == 4) + aRGBABitmap.Create(rSourceBitmap, 32); + const QImage* pBitmap = (rSourceBitmap.GetBitCount() != 4) + ? static_cast(&rSourceBitmap)->GetQImage() + : aRGBABitmap.GetQImage(); + aImage = pBitmap->convertToFormat(Qt5_DefaultFormat32); + } + + Qt5Painter aPainter(*this); + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + aPainter.setTransform(QTransform(aXRel.getX() / aImage.width(), aXRel.getY() / aImage.width(), + aYRel.getX() / aImage.height(), aYRel.getY() / aImage.height(), + rNull.getX(), rNull.getY())); + aPainter.drawImage(QPoint(0, 0), aImage); + aPainter.update(aImage.rect()); + return true; +} + +bool Qt5Graphics::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, + sal_uInt8 nTransparency) +{ + if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor) + return true; + assert(nTransparency <= 100); + if (nTransparency > 100) + nTransparency = 100; + Qt5Painter aPainter(*this, true, (100 - nTransparency) * (255.0 / 100)); + if (SALCOLOR_NONE != m_aFillColor) + aPainter.fillRect(nX, nY, nWidth, nHeight, aPainter.brush()); + if (SALCOLOR_NONE != m_aLineColor) + aPainter.drawRect(nX, nY, nWidth - 1, nHeight - 1); + aPainter.update(nX, nY, nWidth, nHeight); + return true; +} + +void Qt5Graphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) +{ + char* pForceDpi; + if ((pForceDpi = getenv("SAL_FORCEDPI"))) + { + OString sForceDPI(pForceDpi); + rDPIX = rDPIY = sForceDPI.toInt32(); + return; + } + + if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) + return; + + QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); + rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; + rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; +} + +sal_uInt16 Qt5Graphics::GetBitCount() const { return getFormatBits(m_pQImage->format()); } + +long Qt5Graphics::GetGraphicsWidth() const { return m_pQImage->width(); } + +void Qt5Graphics::SetLineColor() { m_aLineColor = SALCOLOR_NONE; } + +void Qt5Graphics::SetLineColor(Color nColor) { m_aLineColor = nColor; } + +void Qt5Graphics::SetFillColor() { m_aFillColor = SALCOLOR_NONE; } + +void Qt5Graphics::SetFillColor(Color nColor) { m_aFillColor = nColor; } + +void Qt5Graphics::SetXORMode(bool bSet, bool) +{ + if (bSet) + m_eCompositionMode = QPainter::CompositionMode_Xor; + else + m_eCompositionMode = QPainter::CompositionMode_SourceOver; +} + +void Qt5Graphics::SetROPLineColor(SalROPColor /*nROPColor*/) {} + +void Qt5Graphics::SetROPFillColor(SalROPColor /*nROPColor*/) {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Graphics_Text.cxx b/vcl/qt5/Qt5Graphics_Text.cxx new file mode 100644 index 000000000..ded886efd --- /dev/null +++ b/vcl/qt5/Qt5Graphics_Text.cxx @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +void Qt5Graphics::SetTextColor(Color nColor) { m_aTextColor = nColor; } + +void Qt5Graphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel) +{ + // release the text styles + for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i) + { + if (!m_pTextStyle[i]) + break; + m_pTextStyle[i].clear(); + } + + if (!pReqFont) + return; + + m_pTextStyle[nFallbackLevel] = static_cast(pReqFont); +} + +void Qt5Graphics::GetFontMetric(ImplFontMetricDataRef& rFMD, int nFallbackLevel) +{ + QRawFont aRawFont(QRawFont::fromFont(*m_pTextStyle[nFallbackLevel])); + Qt5FontFace::fillAttributesFromQFont(*m_pTextStyle[nFallbackLevel], *rFMD); + + rFMD->ImplCalcLineSpacing(m_pTextStyle[nFallbackLevel].get()); + + rFMD->SetSlant(0); + rFMD->SetWidth(aRawFont.averageCharWidth()); + + rFMD->SetMinKashida(m_pTextStyle[nFallbackLevel]->GetKashidaWidth()); +} + +FontCharMapRef Qt5Graphics::GetFontCharMap() const +{ + if (!m_pTextStyle[0]) + return FontCharMapRef(new FontCharMap()); + return static_cast(m_pTextStyle[0]->GetFontFace())->GetFontCharMap(); +} + +bool Qt5Graphics::GetFontCapabilities(vcl::FontCapabilities& rFontCapabilities) const +{ + if (!m_pTextStyle[0]) + return false; + return static_cast(m_pTextStyle[0]->GetFontFace()) + ->GetFontCapabilities(rFontCapabilities); +} + +void Qt5Graphics::GetDevFontList(PhysicalFontCollection* pPFC) +{ + static const bool bUseFontconfig = (nullptr == getenv("SAL_VCL_QT5_NO_FONTCONFIG")); + + m_pFontCollection = pPFC; + if (pPFC->Count()) + return; + + QFontDatabase aFDB; + FreetypeManager& rFontManager = FreetypeManager::get(); + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + ::std::vector aList; + psp::FastPrintFontInfo aInfo; + + rMgr.getFontList(aList); + for (auto const& elem : aList) + { + if (!rMgr.getFontFastInfo(elem, aInfo)) + continue; + + // normalize face number to the FreetypeManager + int nFaceNum = rMgr.getFontFaceNumber(aInfo.m_nID); + int nVariantNum = rMgr.getFontFaceVariation(aInfo.m_nID); + + // inform FreetypeManager about this font provided by the PsPrint subsystem + FontAttributes aDFA = GenPspGraphics::Info2FontAttributes(aInfo); + aDFA.IncreaseQualityBy(4096); + const OString& rFileName = rMgr.getFontFileSysPath(aInfo.m_nID); + rFontManager.AddFontFile(rFileName, nFaceNum, nVariantNum, aInfo.m_nID, aDFA); + } + + if (bUseFontconfig) + SalGenericInstance::RegisterFontSubstitutors(pPFC); + + for (auto& family : aFDB.families()) + for (auto& style : aFDB.styles(family)) + pPFC->Add(Qt5FontFace::fromQFontDatabase(family, style)); +} + +void Qt5Graphics::ClearDevFontCache() {} + +bool Qt5Graphics::AddTempDevFont(PhysicalFontCollection*, const OUString& /*rFileURL*/, + const OUString& /*rFontName*/) +{ + return false; +} + +bool Qt5Graphics::CreateFontSubset(const OUString& /*rToFile*/, const PhysicalFontFace* /*pFont*/, + const sal_GlyphId* /*pGlyphIds*/, const sal_uInt8* /*pEncoding*/, + sal_Int32* /*pWidths*/, int /*nGlyphs*/, + FontSubsetInfo& /*rInfo*/) +{ + return false; +} + +const void* Qt5Graphics::GetEmbedFontData(const PhysicalFontFace*, long* /*pDataLen*/) +{ + return nullptr; +} + +void Qt5Graphics::FreeEmbedFontData(const void* /*pData*/, long /*nDataLen*/) {} + +void Qt5Graphics::GetGlyphWidths(const PhysicalFontFace* /*pPFF*/, bool /*bVertical*/, + std::vector& /*rWidths*/, Ucs2UIntMap& /*rUnicodeEnc*/) +{ +} + +namespace +{ +class Qt5CommonSalLayout : public GenericSalLayout +{ +public: + Qt5CommonSalLayout(LogicalFontInstance& rLFI) + : GenericSalLayout(rLFI) + { + } + + void SetOrientation(int nOrientation) { mnOrientation = nOrientation; } +}; +} + +std::unique_ptr Qt5Graphics::GetTextLayout(int nFallbackLevel) +{ + assert(m_pTextStyle[nFallbackLevel]); + if (!m_pTextStyle[nFallbackLevel]) + return nullptr; + return std::make_unique(*m_pTextStyle[nFallbackLevel]); +} + +void Qt5Graphics::DrawTextLayout(const GenericSalLayout& rLayout) +{ + const Qt5Font* pFont = static_cast(&rLayout.GetFont()); + assert(pFont); + QRawFont aRawFont(QRawFont::fromFont(*pFont)); + + QVector glyphIndexes; + QVector positions; + + // prevent glyph rotation inside the SalLayout + // probably better to add a parameter to GetNextGlyphs? + Qt5CommonSalLayout* pQt5Layout + = static_cast(const_cast(&rLayout)); + int nOrientation = rLayout.GetOrientation(); + if (nOrientation) + pQt5Layout->SetOrientation(0); + + Point aPos; + const GlyphItem* pGlyph; + int nStart = 0; + while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) + { + glyphIndexes.push_back(pGlyph->glyphId()); + positions.push_back(QPointF(aPos.X(), aPos.Y())); + } + + // seems to be common to try to layout an empty string... + if (positions.empty()) + return; + + if (nOrientation) + pQt5Layout->SetOrientation(nOrientation); + + QGlyphRun aGlyphRun; + aGlyphRun.setPositions(positions); + aGlyphRun.setGlyphIndexes(glyphIndexes); + aGlyphRun.setRawFont(aRawFont); + + Qt5Painter aPainter(*this); + QColor aColor = toQColor(m_aTextColor); + aPainter.setPen(aColor); + + if (nOrientation) + { + // make text position the center of the rotation + // then rotate and move back + QRect window = aPainter.window(); + window.moveTo(-positions[0].x(), -positions[0].y()); + aPainter.setWindow(window); + + QTransform p; + p.rotate(-static_cast(nOrientation) / 10.0); + p.translate(-positions[0].x(), -positions[0].y()); + aPainter.setTransform(p); + } + + aPainter.drawGlyphRun(QPointF(), aGlyphRun); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Instance.cxx b/vcl/qt5/Qt5Instance.cxx new file mode 100644 index 000000000..06b959b91 --- /dev/null +++ b/vcl/qt5/Qt5Instance.cxx @@ -0,0 +1,651 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Qt5SvpVirtualDevice.hxx" +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace +{ +/// TODO: not much Qt5 specific here? could be generalised, esp. for OSX... +/// this subclass allows for the transfer of a closure for running on the main +/// thread, to handle all the thread affine stuff in Qt5; the SolarMutex is +/// "loaned" to the main thread for the execution of the closure. +/// @note it doesn't work to just use "emit" and signals/slots to move calls to +/// the main thread, because the other thread has the SolarMutex; the other +/// thread (typically) cannot release SolarMutex, because then the main thread +/// will handle all sorts of events and whatnot; this design ensures that the +/// main thread only runs the passed closure (unless the closure releases +/// SolarMutex itself, which should probably be avoided). +class Qt5YieldMutex : public SalYieldMutex +{ +public: + /// flag only accessed on main thread: + /// main thread has "borrowed" SolarMutex from another thread + bool m_bNoYieldLock = false; + /// members for communication from non-main thread to main thread + std::mutex m_RunInMainMutex; + std::condition_variable m_InMainCondition; + bool m_isWakeUpMain = false; + std::function m_Closure; ///< code for main thread to run + /// members for communication from main thread to non-main thread + std::condition_variable m_ResultCondition; + bool m_isResultReady = false; + + virtual bool IsCurrentThread() const override; + virtual void doAcquire(sal_uInt32 nLockCount) override; + virtual sal_uInt32 doRelease(bool const bUnlockAll) override; +}; +} + +bool Qt5YieldMutex::IsCurrentThread() const +{ + auto const* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (pSalInst->IsMainThread() && m_bNoYieldLock) + { + return true; // main thread has borrowed SolarMutex + } + return SalYieldMutex::IsCurrentThread(); +} + +void Qt5YieldMutex::doAcquire(sal_uInt32 nLockCount) +{ + auto const* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + SalYieldMutex::doAcquire(nLockCount); + return; + } + if (m_bNoYieldLock) + { + return; // special case for main thread: borrowed from other thread + } + do // main thread acquire... + { + std::function func; // copy of closure on thread stack + { + std::unique_lock g(m_RunInMainMutex); + if (m_aMutex.tryToAcquire()) + { + // if there's a closure, the other thread holds m_aMutex + assert(!m_Closure); + m_isWakeUpMain = false; + --nLockCount; // have acquired once! + ++m_nCount; + break; + } + m_InMainCondition.wait(g, [this]() { return m_isWakeUpMain; }); + m_isWakeUpMain = false; + std::swap(func, m_Closure); + } + if (func) + { + assert(!m_bNoYieldLock); + m_bNoYieldLock = true; // execute closure with borrowed SolarMutex + func(); + m_bNoYieldLock = false; + std::scoped_lock g(m_RunInMainMutex); + assert(!m_isResultReady); + m_isResultReady = true; + m_ResultCondition.notify_all(); // unblock other thread + } + } while (true); + SalYieldMutex::doAcquire(nLockCount); +} + +sal_uInt32 Qt5YieldMutex::doRelease(bool const bUnlockAll) +{ + auto const* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (pSalInst->IsMainThread() && m_bNoYieldLock) + { + return 1; // dummy value + } + + std::scoped_lock g(m_RunInMainMutex); + // read m_nCount before doRelease (it's guarded by m_aMutex) + bool const isReleased(bUnlockAll || m_nCount == 1); + sal_uInt32 nCount = SalYieldMutex::doRelease(bUnlockAll); + if (isReleased && !pSalInst->IsMainThread()) + { + m_isWakeUpMain = true; + m_InMainCondition.notify_all(); // unblock main thread + } + return nCount; +} + +// this could be abstracted to be independent of Qt5 by passing in the +// event-trigger as another function parameter... +// it could also be a template of the return type, then it could return the +// result of func... but then how to handle the result in doAcquire? +void Qt5Instance::RunInMainThread(std::function func) +{ + DBG_TESTSOLARMUTEX(); + if (IsMainThread()) + { + func(); + return; + } + + Qt5YieldMutex* const pMutex(static_cast(GetYieldMutex())); + { + std::scoped_lock g(pMutex->m_RunInMainMutex); + assert(!pMutex->m_Closure); + pMutex->m_Closure = func; + // unblock main thread in case it is blocked on condition + pMutex->m_isWakeUpMain = true; + pMutex->m_InMainCondition.notify_all(); + } + // wake up main thread in case it is blocked on event queue + // TriggerUserEventProcessing() appears to be insufficient in case the + // main thread does QEventLoop::WaitForMoreEvents + Q_EMIT ImplRunInMainSignal(); + { + std::unique_lock g(pMutex->m_RunInMainMutex); + pMutex->m_ResultCondition.wait(g, [pMutex]() { return pMutex->m_isResultReady; }); + pMutex->m_isResultReady = false; + } +} + +void Qt5Instance::ImplRunInMain() +{ + SolarMutexGuard g; // trigger the dispatch code in Qt5YieldMutex::doAcquire + (void)this; // suppress unhelpful [loplugin:staticmethods]; can't be static +} + +Qt5Instance::Qt5Instance(std::unique_ptr& pQApp, bool bUseCairo) + : SalGenericInstance(std::make_unique()) + , m_postUserEventId(-1) + , m_bUseCairo(bUseCairo) + , m_pQApplication(std::move(pQApp)) + , m_aUpdateStyleTimer("vcl::qt5 m_aUpdateStyleTimer") + , m_bUpdateFonts(false) +{ + ImplSVData* pSVData = ImplGetSVData(); + if (bUseCairo) + pSVData->maAppData.mxToolkitName = OUString("qt5+cairo"); + else + pSVData->maAppData.mxToolkitName = OUString("qt5"); + + m_postUserEventId = QEvent::registerEventType(); + + // this one needs to be blocking, so that the handling in main thread + // is processed before the thread emitting the signal continues + connect(this, SIGNAL(ImplYieldSignal(bool, bool)), this, SLOT(ImplYield(bool, bool)), + Qt::BlockingQueuedConnection); + connect(this, &Qt5Instance::ImplRunInMainSignal, this, &Qt5Instance::ImplRunInMain, + Qt::QueuedConnection); // no Blocking! + + // this one needs to be queued non-blocking + // in order to have this event arriving to correct event processing loop + connect(this, &Qt5Instance::deleteObjectLaterSignal, this, + [](QObject* pObject) { Qt5Instance::deleteObjectLater(pObject); }, + Qt::QueuedConnection); + + m_aUpdateStyleTimer.SetTimeout(50); + m_aUpdateStyleTimer.SetInvokeHandler(LINK(this, Qt5Instance, updateStyleHdl)); +} + +Qt5Instance::~Qt5Instance() +{ + // force freeing the QApplication before freeing the arguments, + // as it uses references to the provided arguments! + m_pQApplication.reset(); +} + +void Qt5Instance::AfterAppInit() +{ + // set the default application icon via desktop file just on Wayland, + // as this otherwise overrides the individual desktop icons on X11. + if (QGuiApplication::platformName() == "wayland") + QGuiApplication::setDesktopFileName(QStringLiteral("libreoffice-startcenter.desktop")); + QGuiApplication::setLayoutDirection(AllSettings::GetLayoutRTL() ? Qt::RightToLeft + : Qt::LeftToRight); +} + +void Qt5Instance::deleteObjectLater(QObject* pObject) { pObject->deleteLater(); } + +SalFrame* Qt5Instance::CreateChildFrame(SystemParentData* /*pParent*/, SalFrameStyleFlags nStyle) +{ + return new Qt5Frame(nullptr, nStyle, m_bUseCairo); +} + +SalFrame* Qt5Instance::CreateFrame(SalFrame* pParent, SalFrameStyleFlags nStyle) +{ + assert(!pParent || dynamic_cast(pParent)); + return new Qt5Frame(static_cast(pParent), nStyle, m_bUseCairo); +} + +void Qt5Instance::DestroyFrame(SalFrame* pFrame) +{ + if (pFrame) + { + assert(dynamic_cast(pFrame)); + Q_EMIT deleteObjectLaterSignal(static_cast(pFrame)); + } +} + +SalObject* Qt5Instance::CreateObject(SalFrame* pParent, SystemWindowData*, bool bShow) +{ + assert(!pParent || dynamic_cast(pParent)); + return new Qt5Object(static_cast(pParent), bShow); +} + +void Qt5Instance::DestroyObject(SalObject* pObject) +{ + if (pObject) + { + assert(dynamic_cast(pObject)); + Q_EMIT deleteObjectLaterSignal(static_cast(pObject)); + } +} + +std::unique_ptr Qt5Instance::CreateVirtualDevice(SalGraphics* pGraphics, + long& nDX, long& nDY, + DeviceFormat eFormat, + const SystemGraphicsData* pGd) +{ + if (m_bUseCairo) + { + SvpSalGraphics* pSvpSalGraphics = dynamic_cast(pGraphics); + assert(pSvpSalGraphics); + // tdf#127529 see SvpSalInstance::CreateVirtualDevice for the rare case of a non-null pPreExistingTarget + cairo_surface_t* pPreExistingTarget + = pGd ? static_cast(pGd->pSurface) : nullptr; + std::unique_ptr pVD( + new Qt5SvpVirtualDevice(eFormat, pSvpSalGraphics->getSurface(), pPreExistingTarget)); + pVD->SetSize(nDX, nDY); + return pVD; + } + else + { + std::unique_ptr pVD(new Qt5VirtualDevice(eFormat, 1)); + pVD->SetSize(nDX, nDY); + return pVD; + } +} + +std::unique_ptr Qt5Instance::CreateMenu(bool bMenuBar, Menu* pVCLMenu) +{ + std::unique_ptr pRet; + RunInMainThread([&pRet, bMenuBar, pVCLMenu]() { + Qt5Menu* pSalMenu = new Qt5Menu(bMenuBar); + pRet.reset(pSalMenu); + pSalMenu->SetMenu(pVCLMenu); + }); + assert(pRet); + return pRet; +} + +std::unique_ptr Qt5Instance::CreateMenuItem(const SalItemParams& rItemData) +{ + return std::unique_ptr(new Qt5MenuItem(&rItemData)); +} + +SalTimer* Qt5Instance::CreateSalTimer() { return new Qt5Timer(); } + +SalSystem* Qt5Instance::CreateSalSystem() { return new Qt5System; } + +std::shared_ptr Qt5Instance::CreateSalBitmap() +{ + if (m_bUseCairo) + return std::make_shared(); + else + return std::make_shared(); +} + +bool Qt5Instance::ImplYield(bool bWait, bool bHandleAllCurrentEvents) +{ + // Re-acquire the guard for user events when called via Q_EMIT ImplYieldSignal + SolarMutexGuard aGuard; + bool wasEvent = DispatchUserEvents(bHandleAllCurrentEvents); + if (!bHandleAllCurrentEvents && wasEvent) + return true; + + /** + * Quoting the Qt docs: [QAbstractEventDispatcher::processEvents] processes + * pending events that match flags until there are no more events to process. + */ + SolarMutexReleaser aReleaser; + QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + if (bWait && !wasEvent) + wasEvent = dispatcher->processEvents(QEventLoop::WaitForMoreEvents); + else + wasEvent = dispatcher->processEvents(QEventLoop::AllEvents) || wasEvent; + return wasEvent; +} + +bool Qt5Instance::DoYield(bool bWait, bool bHandleAllCurrentEvents) +{ + bool bWasEvent = false; + if (qApp->thread() == QThread::currentThread()) + { + bWasEvent = ImplYield(bWait, bHandleAllCurrentEvents); + if (bWasEvent) + m_aWaitingYieldCond.set(); + } + else + { + { + SolarMutexReleaser aReleaser; + bWasEvent = Q_EMIT ImplYieldSignal(false, bHandleAllCurrentEvents); + } + if (!bWasEvent && bWait) + { + m_aWaitingYieldCond.reset(); + SolarMutexReleaser aReleaser; + m_aWaitingYieldCond.wait(); + bWasEvent = true; + } + } + return bWasEvent; +} + +bool Qt5Instance::AnyInput(VclInputFlags /*nType*/) { return false; } + +OUString Qt5Instance::GetConnectionIdentifier() { return OUString(); } + +void Qt5Instance::AddToRecentDocumentList(const OUString&, const OUString&, const OUString&) {} + +OpenGLContext* Qt5Instance::CreateOpenGLContext() { return new Qt5OpenGLContext; } + +bool Qt5Instance::IsMainThread() const +{ + return !qApp || (qApp->thread() == QThread::currentThread()); +} + +void Qt5Instance::TriggerUserEventProcessing() +{ + QApplication::postEvent(this, new QEvent(QEvent::Type(m_postUserEventId))); +} + +void Qt5Instance::ProcessEvent(SalUserEvent aEvent) +{ + aEvent.m_pFrame->CallCallback(aEvent.m_nEvent, aEvent.m_pData); +} + +Qt5FilePicker* +Qt5Instance::createPicker(css::uno::Reference const& context, + QFileDialog::FileMode eMode) +{ + if (!IsMainThread()) + { + SolarMutexGuard g; + Qt5FilePicker* pPicker; + RunInMainThread([&, this]() { pPicker = createPicker(context, eMode); }); + assert(pPicker); + return pPicker; + } + + return new Qt5FilePicker(context, eMode); +} + +css::uno::Reference +Qt5Instance::createFilePicker(const css::uno::Reference& context) +{ + return css::uno::Reference( + createPicker(context, QFileDialog::ExistingFile)); +} + +css::uno::Reference +Qt5Instance::createFolderPicker(const css::uno::Reference& context) +{ + return css::uno::Reference( + createPicker(context, QFileDialog::Directory)); +} + +css::uno::Reference +Qt5Instance::CreateClipboard(const css::uno::Sequence& arguments) +{ + OUString sel; + if (arguments.getLength() == 0) + { + sel = "CLIPBOARD"; + } + else if (arguments.getLength() != 1 || !(arguments[0] >>= sel)) + { + throw css::lang::IllegalArgumentException("bad Qt5Instance::CreateClipboard arguments", + css::uno::Reference(), -1); + } + + // This could also use RunInMain, but SolarMutexGuard is enough + // since at this point we're not accessing the clipboard, just get the + // accessor to the clipboard. + SolarMutexGuard aGuard; + + auto it = m_aClipboards.find(sel); + if (it != m_aClipboards.end()) + return it->second; + + css::uno::Reference xClipboard = Qt5Clipboard::create(sel); + if (xClipboard.is()) + m_aClipboards[sel] = xClipboard; + + return xClipboard; +} + +css::uno::Reference Qt5Instance::CreateDragSource() +{ + return css::uno::Reference( + static_cast(new Qt5DragSource())); +} + +css::uno::Reference Qt5Instance::CreateDropTarget() +{ + return css::uno::Reference( + static_cast(new Qt5DropTarget())); +} + +IMPL_LINK_NOARG(Qt5Instance, updateStyleHdl, Timer*, void) +{ + SolarMutexGuard aGuard; + SalFrame* pFrame = anyFrame(); + if (pFrame) + { + pFrame->CallCallback(SalEvent::SettingsChanged, nullptr); + if (m_bUpdateFonts) + { + pFrame->CallCallback(SalEvent::FontChanged, nullptr); + m_bUpdateFonts = false; + } + } +} + +void Qt5Instance::UpdateStyle(bool bFontsChanged) +{ + if (bFontsChanged) + m_bUpdateFonts = true; + if (!m_aUpdateStyleTimer.IsActive()) + m_aUpdateStyleTimer.Start(); +} + +void* Qt5Instance::CreateGStreamerSink(const SystemChildWindow* pWindow) +{ +#if ENABLE_GSTREAMER_1_0 && QT5_HAVE_GOBJECT + auto pSymbol = gstElementFactoryNameSymbol(); + if (!pSymbol) + return nullptr; + + const SystemEnvData* pEnvData = pWindow->GetSystemData(); + if (!pEnvData) + return nullptr; + + if (pEnvData->platform != SystemEnvData::Platform::Wayland) + return nullptr; + + GstElement* pVideosink = pSymbol("qwidget5videosink", "qwidget5videosink"); + if (pVideosink) + { + QWidget* pQWidget = static_cast(pEnvData->pWidget); + g_object_set(G_OBJECT(pVideosink), "widget", pQWidget, nullptr); + } + else + { + SAL_WARN("vcl.qt5", "Couldn't initialize qwidget5videosink." + " Video playback might not work as expected." + " Please install Qt5 packages for QtGStreamer."); + // with no videosink explicitly set, GStreamer will open its own (misplaced) window(s) to display video + } + + return pVideosink; +#else + (void*)pWindow; + return nullptr; +#endif +} + +void Qt5Instance::AllocFakeCmdlineArgs(std::unique_ptr& rFakeArgv, + std::unique_ptr& rFakeArgc, + std::vector& rFakeArgvFreeable) +{ + OString aVersion(qVersion()); + SAL_INFO("vcl.qt5", "qt version string is " << aVersion); + + const sal_uInt32 nParams = osl_getCommandArgCount(); + OString aDisplay; + sal_uInt32 nDisplayValueIdx = 0; + OUString aParam, aBin; + + for (sal_uInt32 nIdx = 0; nIdx < nParams; ++nIdx) + { + osl_getCommandArg(nIdx, &aParam.pData); + if (aParam != "-display") + continue; + ++nIdx; + nDisplayValueIdx = nIdx; + } + + osl_getExecutableFile(&aParam.pData); + osl_getSystemPathFromFileURL(aParam.pData, &aBin.pData); + OString aExec = OUStringToOString(aBin, osl_getThreadTextEncoding()); + + std::vector aFakeArgvFreeable; + aFakeArgvFreeable.reserve(4); + aFakeArgvFreeable.emplace_back(strdup(aExec.getStr())); + aFakeArgvFreeable.emplace_back(strdup("--nocrashhandler")); + if (nDisplayValueIdx) + { + aFakeArgvFreeable.emplace_back(strdup("-display")); + osl_getCommandArg(nDisplayValueIdx, &aParam.pData); + aDisplay = OUStringToOString(aParam, osl_getThreadTextEncoding()); + aFakeArgvFreeable.emplace_back(strdup(aDisplay.getStr())); + } + rFakeArgvFreeable.swap(aFakeArgvFreeable); + + const int nFakeArgc = rFakeArgvFreeable.size(); + rFakeArgv.reset(new char*[nFakeArgc]); + for (int i = 0; i < nFakeArgc; i++) + rFakeArgv[i] = rFakeArgvFreeable[i].get(); + + rFakeArgc.reset(new int); + *rFakeArgc = nFakeArgc; +} + +void Qt5Instance::MoveFakeCmdlineArgs(std::unique_ptr& rFakeArgv, + std::unique_ptr& rFakeArgc, + std::vector& rFakeArgvFreeable) +{ + m_pFakeArgv = std::move(rFakeArgv); + m_pFakeArgc = std::move(rFakeArgc); + m_pFakeArgvFreeable.swap(rFakeArgvFreeable); +} + +std::unique_ptr Qt5Instance::CreateQApplication(int& nArgc, char** pArgv) +{ + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + // for scaled icons in the native menus + QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + + FreeableCStr session_manager; + if (getenv("SESSION_MANAGER") != nullptr) + { + session_manager.reset(strdup(getenv("SESSION_MANAGER"))); + unsetenv("SESSION_MANAGER"); + } + + std::unique_ptr pQApp = std::make_unique(nArgc, pArgv); + + if (session_manager != nullptr) + { + // coverity[tainted_string] - trusted source for setenv + setenv("SESSION_MANAGER", session_manager.get(), 1); + } + + QApplication::setQuitOnLastWindowClosed(false); + return pQApp; +} + +extern "C" { +VCLPLUG_QT5_PUBLIC SalInstance* create_SalInstance() +{ + static const bool bUseCairo = (nullptr != getenv("SAL_VCL_QT5_USE_CAIRO")); + + std::unique_ptr pFakeArgv; + std::unique_ptr pFakeArgc; + std::vector aFakeArgvFreeable; + Qt5Instance::AllocFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); + + std::unique_ptr pQApp + = Qt5Instance::CreateQApplication(*pFakeArgc, pFakeArgv.get()); + + Qt5Instance* pInstance = new Qt5Instance(pQApp, bUseCairo); + pInstance->MoveFakeCmdlineArgs(pFakeArgv, pFakeArgc, aFakeArgvFreeable); + + new Qt5Data(pInstance); + + return pInstance; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Instance_Print.cxx b/vcl/qt5/Qt5Instance_Print.cxx new file mode 100644 index 000000000..cab5757a3 --- /dev/null +++ b/vcl/qt5/Qt5Instance_Print.cxx @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +using namespace psp; + +/* + * static helpers + */ + +static OUString getPdfDir(const PrinterInfo& rInfo) +{ + OUString aDir; + sal_Int32 nIndex = 0; + while (nIndex != -1) + { + OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); + if (aToken.startsWith("pdf=")) + { + sal_Int32 nPos = 0; + aDir = aToken.getToken(1, '=', nPos); + if (aDir.isEmpty()) + aDir = OStringToOUString(OString(getenv("HOME")), osl_getThreadTextEncoding()); + break; + } + } + return aDir; +} + +SalInfoPrinter* Qt5Instance::CreateInfoPrinter(SalPrinterQueueInfo* pQueueInfo, + ImplJobSetup* pJobSetup) +{ + // create and initialize SalInfoPrinter + PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; + configurePspInfoPrinter(pPrinter, pQueueInfo, pJobSetup); + + return pPrinter; +} + +void Qt5Instance::DestroyInfoPrinter(SalInfoPrinter* pPrinter) { delete pPrinter; } + +std::unique_ptr Qt5Instance::CreatePrinter(SalInfoPrinter* pInfoPrinter) +{ + // create and initialize SalPrinter + Qt5Printer* pPrinter = new Qt5Printer(pInfoPrinter); + pPrinter->m_aJobData = static_cast(pInfoPrinter)->m_aJobData; + + return std::unique_ptr(pPrinter); +} + +void Qt5Instance::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::vector aPrinters; + rManager.listPrinters(aPrinters); + + for (const auto& rPrinter : aPrinters) + { + const PrinterInfo& rInfo(rManager.getPrinterInfo(rPrinter)); + // create new entry + std::unique_ptr pInfo(new SalPrinterQueueInfo); + pInfo->maPrinterName = rPrinter; + pInfo->maDriver = rInfo.m_aDriverName; + pInfo->maLocation = rInfo.m_aLocation; + pInfo->maComment = rInfo.m_aComment; + + sal_Int32 nIndex = 0; + while (nIndex != -1) + { + OUString aToken(rInfo.m_aFeatures.getToken(0, ',', nIndex)); + if (aToken.startsWith("pdf=")) + { + pInfo->maLocation = getPdfDir(rInfo); + break; + } + } + + pList->Add(std::move(pInfo)); + } +} + +void Qt5Instance::GetPrinterQueueState(SalPrinterQueueInfo*) {} + +OUString Qt5Instance::GetDefaultPrinter() +{ + PrinterInfoManager& rManager(PrinterInfoManager::get()); + return rManager.getDefaultPrinter(); +} + +void Qt5Instance::PostPrintersChanged() {} + +std::unique_ptr Qt5Instance::CreatePrintGraphics() +{ + return std::make_unique(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5MainWindow.cxx b/vcl/qt5/Qt5MainWindow.cxx new file mode 100644 index 000000000..45d726ba2 --- /dev/null +++ b/vcl/qt5/Qt5MainWindow.cxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include +#include +#include + +#include +#include + +Qt5MainWindow::Qt5MainWindow(Qt5Frame& rFrame, Qt::WindowFlags f) + : QMainWindow(nullptr, f) + , m_rFrame(rFrame) +{ + QAccessible::installFactory(Qt5AccessibleWidget::customFactory); +} + +void Qt5MainWindow::closeEvent(QCloseEvent* pEvent) +{ + bool bRet = false; + bRet = m_rFrame.CallCallback(SalEvent::Close, nullptr); + + if (bRet) + pEvent->accept(); + // SalEvent::Close returning false may mean that user has vetoed + // closing the frame ("you have unsaved changes" dialog for example) + // We shouldn't process the event in such case + else + pEvent->ignore(); +} + +void Qt5MainWindow::moveEvent(QMoveEvent* pEvent) +{ + const qreal fRatio = m_rFrame.devicePixelRatioF(); + m_rFrame.maGeometry.nX = round(pEvent->pos().x() * fRatio); + m_rFrame.maGeometry.nY = round(pEvent->pos().y() * fRatio); + m_rFrame.CallCallback(SalEvent::Move, nullptr); +} diff --git a/vcl/qt5/Qt5Menu.cxx b/vcl/qt5/Qt5Menu.cxx new file mode 100644 index 000000000..986152470 --- /dev/null +++ b/vcl/qt5/Qt5Menu.cxx @@ -0,0 +1,704 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +Qt5Menu::Qt5Menu(bool bMenuBar) + : mpVCLMenu(nullptr) + , mpParentSalMenu(nullptr) + , mpFrame(nullptr) + , mbMenuBar(bMenuBar) + , mpQMenuBar(nullptr) + , mpQMenu(nullptr) + , mpCloseButton(nullptr) +{ +} + +bool Qt5Menu::VisibleMenuBar() { return true; } + +void Qt5Menu::InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos) +{ + sal_uInt16 nId = pSalMenuItem->mnId; + OUString aText = mpVCLMenu->GetItemText(nId); + NativeItemText(aText); + vcl::KeyCode nAccelKey = mpVCLMenu->GetAccelKey(nId); + + pSalMenuItem->mpAction.reset(); + pSalMenuItem->mpMenu.reset(); + + if (mbMenuBar) + { + // top-level menu + if (mpQMenuBar) + { + QMenu* pQMenu = new QMenu(toQString(aText), nullptr); + pSalMenuItem->mpMenu.reset(pQMenu); + + if ((nPos != MENU_APPEND) + && (static_cast(nPos) < o3tl::make_unsigned(mpQMenuBar->actions().size()))) + { + mpQMenuBar->insertMenu(mpQMenuBar->actions()[nPos], pQMenu); + } + else + { + mpQMenuBar->addMenu(pQMenu); + } + + // correct parent menu for generated menu + if (pSalMenuItem->mpSubMenu) + { + pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; + } + + connect(pQMenu, &QMenu::aboutToShow, this, + [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); + connect(pQMenu, &QMenu::aboutToHide, this, + [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); + } + } + else + { + if (!mpQMenu) + { + // no QMenu set, instantiate own one + mpOwnedQMenu.reset(new QMenu); + mpQMenu = mpOwnedQMenu.get(); + } + + if (pSalMenuItem->mpSubMenu) + { + // submenu + QMenu* pQMenu = new QMenu(toQString(aText), nullptr); + pSalMenuItem->mpMenu.reset(pQMenu); + + if ((nPos != MENU_APPEND) + && (static_cast(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertMenu(mpQMenu->actions()[nPos], pQMenu); + } + else + { + mpQMenu->addMenu(pQMenu); + } + + // correct parent menu for generated menu + pSalMenuItem->mpSubMenu->mpQMenu = pQMenu; + + ReinitializeActionGroup(nPos); + + // clear all action groups since menu is recreated + pSalMenuItem->mpSubMenu->ResetAllActionGroups(); + + connect(pQMenu, &QMenu::aboutToShow, this, + [pSalMenuItem] { slotMenuAboutToShow(pSalMenuItem); }); + connect(pQMenu, &QMenu::aboutToHide, this, + [pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); }); + } + else + { + if (pSalMenuItem->mnType == MenuItemType::SEPARATOR) + { + QAction* pAction = new QAction(nullptr); + pSalMenuItem->mpAction.reset(pAction); + pAction->setSeparator(true); + + if ((nPos != MENU_APPEND) + && (static_cast(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); + } + else + { + mpQMenu->addAction(pAction); + } + + ReinitializeActionGroup(nPos); + } + else + { + // leaf menu + QAction* pAction = new QAction(toQString(aText), nullptr); + pSalMenuItem->mpAction.reset(pAction); + + if ((nPos != MENU_APPEND) + && (static_cast(nPos) < o3tl::make_unsigned(mpQMenu->actions().size()))) + { + mpQMenu->insertAction(mpQMenu->actions()[nPos], pAction); + } + else + { + mpQMenu->addAction(pAction); + } + + ReinitializeActionGroup(nPos); + + UpdateActionGroupItem(pSalMenuItem); + + const Qt5Frame* pFrame = GetFrame(); + if (pFrame) + pAction->setShortcut(toQString(nAccelKey.GetName(pFrame->GetWindow()))); + + connect(pAction, &QAction::triggered, this, + [pSalMenuItem] { slotMenuTriggered(pSalMenuItem); }); + } + } + } + + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + pAction->setEnabled(pSalMenuItem->mbEnabled); + pAction->setVisible(pSalMenuItem->mbVisible); + } +} + +void Qt5Menu::ReinitializeActionGroup(unsigned nPos) +{ + const unsigned nCount = GetItemCount(); + + if (nCount == 0) + { + return; + } + + if (nPos == MENU_APPEND) + { + nPos = nCount - 1; + } + else if (nPos >= nCount) + { + return; + } + + Qt5MenuItem* pPrevItem = (nPos > 0) ? GetItemAtPos(nPos - 1) : nullptr; + Qt5MenuItem* pCurrentItem = GetItemAtPos(nPos); + Qt5MenuItem* pNextItem = (nPos < nCount - 1) ? GetItemAtPos(nPos + 1) : nullptr; + + if (pCurrentItem->mnType == MenuItemType::SEPARATOR) + { + pCurrentItem->mpActionGroup.reset(); + + // if it's inserted into middle of existing group, split it into two groups: + // first goes original group, after separator goes new group + if (pPrevItem && pPrevItem->mpActionGroup && pNextItem && pNextItem->mpActionGroup + && (pPrevItem->mpActionGroup == pNextItem->mpActionGroup)) + { + std::shared_ptr pFirstActionGroup = pPrevItem->mpActionGroup; + auto pSecondActionGroup = std::make_shared(nullptr); + pSecondActionGroup->setExclusive(true); + + auto actions = pFirstActionGroup->actions(); + + for (unsigned idx = nPos + 1; idx < nCount; ++idx) + { + Qt5MenuItem* pModifiedItem = GetItemAtPos(idx); + + if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) + { + break; + } + + pModifiedItem->mpActionGroup = pSecondActionGroup; + auto action = pModifiedItem->getAction(); + + if (actions.contains(action)) + { + pFirstActionGroup->removeAction(action); + pSecondActionGroup->addAction(action); + } + } + } + } + else + { + if (!pCurrentItem->mpActionGroup) + { + // unless element is inserted between two separators, or a separator and an end of vector, use neighbouring group since it's shared + if (pPrevItem && pPrevItem->mpActionGroup) + { + pCurrentItem->mpActionGroup = pPrevItem->mpActionGroup; + } + else if (pNextItem && pNextItem->mpActionGroup) + { + pCurrentItem->mpActionGroup = pNextItem->mpActionGroup; + } + else + { + pCurrentItem->mpActionGroup = std::make_shared(nullptr); + pCurrentItem->mpActionGroup->setExclusive(true); + } + } + + // if there's also a different group after this element, merge it + if (pNextItem && pNextItem->mpActionGroup + && (pCurrentItem->mpActionGroup != pNextItem->mpActionGroup)) + { + auto pFirstCheckedAction = pCurrentItem->mpActionGroup->checkedAction(); + auto pSecondCheckedAction = pNextItem->mpActionGroup->checkedAction(); + auto actions = pNextItem->mpActionGroup->actions(); + + // first move all actions from second group to first one, and if first group already has checked action, + // and second group also has a checked action, uncheck action from second group + for (auto action : actions) + { + pNextItem->mpActionGroup->removeAction(action); + + if (pFirstCheckedAction && pSecondCheckedAction && (action == pSecondCheckedAction)) + { + action->setChecked(false); + } + + pCurrentItem->mpActionGroup->addAction(action); + } + + // now replace all pointers to second group with pointers to first group + for (unsigned idx = nPos + 1; idx < nCount; ++idx) + { + Qt5MenuItem* pModifiedItem = GetItemAtPos(idx); + + if ((!pModifiedItem) || (!pModifiedItem->mpActionGroup)) + { + break; + } + + pModifiedItem->mpActionGroup = pCurrentItem->mpActionGroup; + } + } + } +} + +void Qt5Menu::ResetAllActionGroups() +{ + for (unsigned nItem = 0; nItem < GetItemCount(); ++nItem) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem); + pSalMenuItem->mpActionGroup.reset(); + } +} + +void Qt5Menu::UpdateActionGroupItem(const Qt5MenuItem* pSalMenuItem) +{ + QAction* pAction = pSalMenuItem->getAction(); + if (!pAction) + return; + + bool bChecked = mpVCLMenu->IsItemChecked(pSalMenuItem->mnId); + MenuItemBits itemBits = mpVCLMenu->GetItemBits(pSalMenuItem->mnId); + + if (itemBits & MenuItemBits::RADIOCHECK) + { + pAction->setCheckable(true); + + if (pSalMenuItem->mpActionGroup) + { + pSalMenuItem->mpActionGroup->addAction(pAction); + } + + pAction->setChecked(bChecked); + } + else + { + pAction->setActionGroup(nullptr); + + if (itemBits & MenuItemBits::CHECKABLE) + { + pAction->setCheckable(true); + pAction->setChecked(bChecked); + } + else + { + pAction->setChecked(false); + pAction->setCheckable(false); + } + } +} + +void Qt5Menu::InsertItem(SalMenuItem* pSalMenuItem, unsigned nPos) +{ + SolarMutexGuard aGuard; + Qt5MenuItem* pItem = static_cast(pSalMenuItem); + + if (nPos == MENU_APPEND) + maItems.push_back(pItem); + else + maItems.insert(maItems.begin() + nPos, pItem); + + pItem->mpParentMenu = this; + + InsertMenuItem(pItem, nPos); +} + +void Qt5Menu::RemoveItem(unsigned nPos) +{ + SolarMutexGuard aGuard; + + if (nPos < maItems.size()) + { + Qt5MenuItem* pItem = maItems[nPos]; + pItem->mpAction.reset(); + pItem->mpMenu.reset(); + + maItems.erase(maItems.begin() + nPos); + + // Recalculate action groups if necessary: + // if separator between two QActionGroups was removed, + // it may be needed to merge them + if (nPos > 0) + { + ReinitializeActionGroup(nPos - 1); + } + } +} + +void Qt5Menu::SetSubMenu(SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos) +{ + SolarMutexGuard aGuard; + Qt5MenuItem* pItem = static_cast(pSalMenuItem); + Qt5Menu* pQSubMenu = static_cast(pSubMenu); + + pItem->mpSubMenu = pQSubMenu; + // at this point the pointer to parent menu may be outdated, update it too + pItem->mpParentMenu = this; + + if (pQSubMenu != nullptr) + { + pQSubMenu->mpParentSalMenu = this; + pQSubMenu->mpQMenu = pItem->mpMenu.get(); + } + + // if it's not a menu bar item, then convert it to corresponding item if type if necessary. + // If submenu is present and it's an action, convert it to menu. + // If submenu is not present and it's a menu, convert it to action. + // It may be fine to proceed in any case, but by skipping other cases + // amount of unneeded actions taken should be reduced. + if (pItem->mpParentMenu->mbMenuBar || (pQSubMenu && pItem->mpMenu) + || ((!pQSubMenu) && pItem->mpAction)) + { + return; + } + + InsertMenuItem(pItem, nPos); +} + +void Qt5Menu::SetFrame(const SalFrame* pFrame) +{ + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + if (!pSalInst->IsMainThread()) + { + pSalInst->RunInMainThread([this, pFrame]() { SetFrame(pFrame); }); + return; + } + + SolarMutexGuard aGuard; + assert(mbMenuBar); + mpFrame = const_cast(static_cast(pFrame)); + + mpFrame->SetMenu(this); + + Qt5MainWindow* pMainWindow = mpFrame->GetTopLevelWindow(); + if (pMainWindow) + { + mpQMenuBar = pMainWindow->menuBar(); + if (mpQMenuBar) + { + mpQMenuBar->clear(); + QPushButton* pButton + = static_cast(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); + if (pButton && ((mpCloseButton != pButton) || !maCloseButtonConnection)) + { + maCloseButtonConnection + = connect(pButton, &QPushButton::clicked, this, &Qt5Menu::slotCloseDocument); + mpCloseButton = pButton; + } + } + + mpQMenu = nullptr; + + DoFullMenuUpdate(mpVCLMenu); + } +} + +void Qt5Menu::DoFullMenuUpdate(Menu* pMenuBar) +{ + // clear action groups since menu is rebuilt + ResetAllActionGroups(); + ShowCloseButton(false); + + for (sal_Int32 nItem = 0; nItem < static_cast(GetItemCount()); nItem++) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem); + InsertMenuItem(pSalMenuItem, nItem); + SetItemImage(nItem, pSalMenuItem, pSalMenuItem->maImage); + const bool bShowDisabled + = bool(pMenuBar->GetMenuFlags() & MenuFlags::AlwaysShowDisabledEntries) + || !bool(pMenuBar->GetMenuFlags() & MenuFlags::HideDisabledEntries); + const bool bVisible = bShowDisabled || mpVCLMenu->IsItemEnabled(pSalMenuItem->mnId); + pSalMenuItem->getAction()->setVisible(bVisible); + + if (pSalMenuItem->mpSubMenu != nullptr) + { + pMenuBar->HandleMenuActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); + pSalMenuItem->mpSubMenu->DoFullMenuUpdate(pMenuBar); + pMenuBar->HandleMenuDeActivateEvent(pSalMenuItem->mpSubMenu->GetMenu()); + } + } +} + +void Qt5Menu::ShowItem(unsigned nPos, bool bShow) +{ + if (nPos < maItems.size()) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setVisible(bShow); + pSalMenuItem->mbVisible = bShow; + } +} + +void Qt5Menu::SetItemBits(unsigned nPos, MenuItemBits) +{ + if (nPos < maItems.size()) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos); + UpdateActionGroupItem(pSalMenuItem); + } +} + +void Qt5Menu::CheckItem(unsigned nPos, bool bChecked) +{ + if (nPos < maItems.size()) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + pAction->setCheckable(true); + pAction->setChecked(bChecked); + } + } +} + +void Qt5Menu::EnableItem(unsigned nPos, bool bEnable) +{ + if (nPos < maItems.size()) + { + Qt5MenuItem* pSalMenuItem = GetItemAtPos(nPos); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setEnabled(bEnable); + pSalMenuItem->mbEnabled = bEnable; + } +} + +void Qt5Menu::SetItemText(unsigned, SalMenuItem* pItem, const OUString& rText) +{ + Qt5MenuItem* pSalMenuItem = static_cast(pItem); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + { + OUString aText(rText); + NativeItemText(aText); + pAction->setText(toQString(aText)); + } +} + +void Qt5Menu::SetItemImage(unsigned, SalMenuItem* pItem, const Image& rImage) +{ + Qt5MenuItem* pSalMenuItem = static_cast(pItem); + + // Save new image to use it in DoFullMenuUpdate + pSalMenuItem->maImage = rImage; + + QAction* pAction = pSalMenuItem->getAction(); + if (!pAction) + return; + + pAction->setIcon(QPixmap::fromImage(toQImage(rImage))); +} + +void Qt5Menu::SetAccelerator(unsigned, SalMenuItem* pItem, const vcl::KeyCode&, + const OUString& rText) +{ + Qt5MenuItem* pSalMenuItem = static_cast(pItem); + QAction* pAction = pSalMenuItem->getAction(); + if (pAction) + pAction->setShortcut(QKeySequence(toQString(rText), QKeySequence::PortableText)); +} + +void Qt5Menu::GetSystemMenuData(SystemMenuData*) {} + +Qt5Menu* Qt5Menu::GetTopLevel() +{ + Qt5Menu* pMenu = this; + while (pMenu->mpParentSalMenu) + pMenu = pMenu->mpParentSalMenu; + return pMenu; +} + +void Qt5Menu::ShowMenuBar(bool bVisible) +{ + if (mpQMenuBar) + mpQMenuBar->setVisible(bVisible); +} + +const Qt5Frame* Qt5Menu::GetFrame() const +{ + SolarMutexGuard aGuard; + const Qt5Menu* pMenu = this; + while (pMenu && !pMenu->mpFrame) + pMenu = pMenu->mpParentSalMenu; + return pMenu ? pMenu->mpFrame : nullptr; +} + +void Qt5Menu::slotMenuTriggered(Qt5MenuItem* pQItem) +{ + if (pQItem) + { + Qt5Menu* pSalMenu = pQItem->mpParentMenu; + Qt5Menu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + auto mnId = pQItem->mnId; + + // HACK to allow HandleMenuCommandEvent to "not-set" the checked button + // LO expects a signal before an item state change, so reset the check item + if (pQItem->mpAction->isCheckable() + && (!pQItem->mpActionGroup || pQItem->mpActionGroup->actions().size() <= 1)) + pQItem->mpAction->setChecked(!pQItem->mpAction->isChecked()); + pTopLevel->GetMenu()->HandleMenuCommandEvent(pMenu, mnId); + } +} + +void Qt5Menu::slotMenuAboutToShow(Qt5MenuItem* pQItem) +{ + if (pQItem) + { + Qt5Menu* pSalMenu = pQItem->mpSubMenu; + Qt5Menu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + + // following function may update the menu + pTopLevel->GetMenu()->HandleMenuActivateEvent(pMenu); + } +} + +void Qt5Menu::slotMenuAboutToHide(Qt5MenuItem* pQItem) +{ + if (pQItem) + { + Qt5Menu* pSalMenu = pQItem->mpSubMenu; + Qt5Menu* pTopLevel = pSalMenu->GetTopLevel(); + + Menu* pMenu = pSalMenu->GetMenu(); + + pTopLevel->GetMenu()->HandleMenuDeActivateEvent(pMenu); + } +} + +void Qt5Menu::NativeItemText(OUString& rItemText) +{ + // preserve literal '&'s in menu texts + rItemText = rItemText.replaceAll("&", "&&"); + + rItemText = rItemText.replace('~', '&'); +} + +void Qt5Menu::slotCloseDocument() +{ + MenuBar* pVclMenuBar = static_cast(mpVCLMenu.get()); + if (pVclMenuBar) + Application::PostUserEvent(pVclMenuBar->GetCloseButtonClickHdl()); +} + +void Qt5Menu::ShowCloseButton(bool bShow) +{ + if (!mpQMenuBar) + return; + + QPushButton* pButton = static_cast(mpQMenuBar->cornerWidget(Qt::TopRightCorner)); + if (!pButton) + { + QIcon aIcon; + if (QIcon::hasThemeIcon("window-close-symbolic")) + aIcon = QIcon::fromTheme("window-close-symbolic"); + else + aIcon = QIcon( + QPixmap::fromImage((toQImage(Image(StockImage::Yes, SV_RESID_BITMAP_CLOSEDOC))))); + pButton = new QPushButton(mpQMenuBar); + pButton->setIcon(aIcon); + pButton->setFlat(true); + pButton->setFocusPolicy(Qt::NoFocus); + pButton->setToolTip(toQString(VclResId(SV_HELPTEXT_CLOSEDOCUMENT))); + mpQMenuBar->setCornerWidget(pButton, Qt::TopRightCorner); + maCloseButtonConnection + = connect(pButton, &QPushButton::clicked, this, &Qt5Menu::slotCloseDocument); + mpCloseButton = pButton; + } + + if (bShow) + pButton->show(); + else + pButton->hide(); +} + +bool Qt5Menu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, + FloatWinPopupFlags nFlags) +{ + assert(mpQMenu); + DoFullMenuUpdate(mpVCLMenu); + mpQMenu->setTearOffEnabled(bool(nFlags & FloatWinPopupFlags::AllowTearOff)); + + const QPoint aPos = QCursor::pos(); + mpQMenu->exec(aPos); + + return true; +} + +Qt5MenuItem::Qt5MenuItem(const SalItemParams* pItemData) + : mpParentMenu(nullptr) + , mpSubMenu(nullptr) + , mnId(pItemData->nId) + , mnType(pItemData->eType) + , mbVisible(true) + , mbEnabled(true) + , maImage(pItemData->aImage) +{ +} + +QAction* Qt5MenuItem::getAction() const +{ + if (mpMenu) + return mpMenu->menuAction(); + if (mpAction) + return mpAction.get(); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Object.cxx b/vcl/qt5/Qt5Object.cxx new file mode 100644 index 000000000..5bbfef5a5 --- /dev/null +++ b/vcl/qt5/Qt5Object.cxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include + +Qt5Object::Qt5Object(Qt5Frame* pParent, bool bShow) + : m_pParent(pParent) + , m_pQWidget(nullptr) + , m_pQWindow(nullptr) +{ + if (!m_pParent || !pParent->GetQWidget()) + return; + + m_pQWindow = new Qt5ObjectWindow(*this); + m_pQWidget = QWidget::createWindowContainer(m_pQWindow, pParent->GetQWidget()); + m_pQWidget->setAttribute(Qt::WA_NoSystemBackground); + connect(m_pQWidget, &QObject::destroyed, this, [this]() { m_pQWidget = nullptr; }); + + if (bShow) + m_pQWidget->show(); + + m_aSystemData.aShellWindow = reinterpret_cast(this); + //m_aSystemData.pSalFrame = this; + m_aSystemData.pWidget = m_pQWidget; + //m_aSystemData.nScreen = m_nXScreen.getXScreen(); + m_aSystemData.toolkit = SystemEnvData::Toolkit::Qt5; + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + const bool bWayland = QGuiApplication::platformName() == "wayland"; + if (!bWayland) + { + m_aSystemData.platform = SystemEnvData::Platform::Xcb; + m_aSystemData.aWindow = m_pQWindow->winId(); // ID of the embedded window + } + else + { + m_aSystemData.platform = SystemEnvData::Platform::Wayland; + // TODO implement as needed for Wayland, + // s.a. commit c0d4f3ad3307c which did this for gtk3 + // QPlatformNativeInterface* native = QGuiApplication::platformNativeInterface(); + // m_aSystemData.pDisplay = native->nativeResourceForWindow("display", nullptr); + // m_aSystemData.aWindow = reinterpret_cast( + // native->nativeResourceForWindow("surface", m_pQWidget->windowHandle())); + } +} + +Qt5Object::~Qt5Object() +{ + if (m_pQWidget) + { + m_pQWidget->setParent(nullptr); + delete m_pQWidget; + } +} + +void Qt5Object::ResetClipRegion() +{ + if (m_pQWidget) + m_pRegion = QRegion(m_pQWidget->geometry()); + else + m_pRegion = QRegion(); +} + +void Qt5Object::BeginSetClipRegion(sal_uInt32) { m_pRegion = QRegion(); } + +void Qt5Object::UnionClipRegion(long nX, long nY, long nWidth, long nHeight) +{ + m_pRegion += QRect(nX, nY, nWidth, nHeight); +} + +void Qt5Object::EndSetClipRegion() +{ + if (m_pQWidget) + m_pRegion = m_pRegion.intersected(m_pQWidget->geometry()); +} + +void Qt5Object::SetPosSize(long nX, long nY, long nWidth, long nHeight) +{ + if (m_pQWidget) + { + m_pQWidget->move(nX, nY); + m_pQWidget->setFixedSize(nWidth, nHeight); + } +} + +void Qt5Object::Show(bool bVisible) +{ + if (m_pQWidget) + m_pQWidget->setVisible(bVisible); +} + +void Qt5Object::SetForwardKey(bool /*bEnable*/) {} + +Qt5ObjectWindow::Qt5ObjectWindow(Qt5Object& rParent) + : m_rParent(rParent) +{ + assert(m_rParent.frame() && m_rParent.frame()->GetQWidget()); +} + +void Qt5ObjectWindow::focusInEvent(QFocusEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::GetFocus); + QWindow::focusInEvent(pEvent); +} + +void Qt5ObjectWindow::focusOutEvent(QFocusEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::LoseFocus); + QWindow::focusOutEvent(pEvent); +} + +void Qt5ObjectWindow::mousePressEvent(QMouseEvent* pEvent) +{ + m_rParent.CallCallback(SalObjEvent::ToTop); + Qt5Widget::handleMousePressEvent(*m_rParent.frame(), pEvent); +} + +void Qt5ObjectWindow::mouseReleaseEvent(QMouseEvent* pEvent) +{ + Qt5Widget::handleMouseReleaseEvent(*m_rParent.frame(), pEvent); +} + +bool Qt5ObjectWindow::event(QEvent* pEvent) +{ + return Qt5Widget::handleEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent) + || QWindow::event(pEvent); +} + +void Qt5ObjectWindow::keyReleaseEvent(QKeyEvent* pEvent) +{ + if (!Qt5Widget::handleKeyReleaseEvent(*m_rParent.frame(), *m_rParent.widget(), pEvent)) + QWindow::keyReleaseEvent(pEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5OpenGLContext.cxx b/vcl/qt5/Qt5OpenGLContext.cxx new file mode 100644 index 000000000..a33f7abde --- /dev/null +++ b/vcl/qt5/Qt5OpenGLContext.cxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +bool Qt5OpenGLContext::g_bAnyCurrent = false; + +void Qt5OpenGLContext::swapBuffers() +{ + OpenGLZone aZone; + + if (m_pContext && m_pWindow && m_pWindow->isExposed()) + { + m_pContext->swapBuffers(m_pWindow); + } + + BuffersSwapped(); +} + +void Qt5OpenGLContext::resetCurrent() +{ + clearCurrent(); + + OpenGLZone aZone; + + if (m_pContext) + { + m_pContext->doneCurrent(); + g_bAnyCurrent = false; + } +} + +bool Qt5OpenGLContext::isCurrent() +{ + OpenGLZone aZone; + return g_bAnyCurrent && (QOpenGLContext::currentContext() == m_pContext); +} + +bool Qt5OpenGLContext::isAnyCurrent() +{ + OpenGLZone aZone; + return g_bAnyCurrent && (QOpenGLContext::currentContext() != nullptr); +} + +bool Qt5OpenGLContext::ImplInit() +{ + if (!m_pWindow) + { + SAL_WARN("vcl.opengl.qt5", "failed to create window"); + return false; + } + + m_pWindow->setSurfaceType(QSurface::OpenGLSurface); + m_pWindow->create(); + + m_pContext = new QOpenGLContext(m_pWindow); + if (!m_pContext->create()) + { + SAL_WARN("vcl.opengl.qt5", "failed to create context"); + return false; + } + + m_pContext->makeCurrent(m_pWindow); + g_bAnyCurrent = true; + + bool bRet = InitGL(); + InitGLDebugging(); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + registerAsCurrent(); + + return bRet; +} + +void Qt5OpenGLContext::makeCurrent() +{ + if (isCurrent()) + return; + + OpenGLZone aZone; + + clearCurrent(); + + if (m_pContext && m_pWindow) + { + m_pContext->makeCurrent(m_pWindow); + g_bAnyCurrent = true; + } + + registerAsCurrent(); +} + +void Qt5OpenGLContext::destroyCurrentContext() +{ + OpenGLZone aZone; + + if (m_pContext) + { + m_pContext->doneCurrent(); + g_bAnyCurrent = false; + } + + if (glGetError() != GL_NO_ERROR) + { + SAL_WARN("vcl.opengl.qt5", "glError: " << glGetError()); + } +} + +void Qt5OpenGLContext::initWindow() +{ + if (!m_pChildWindow) + { + SystemWindowData winData = generateWinData(mpWindow, mbRequestLegacyContext); + m_pChildWindow = VclPtr::Create(mpWindow, 0, &winData, false); + } + + if (m_pChildWindow) + { + InitChildWindow(m_pChildWindow.get()); + } + + m_pWindow + = static_cast(m_pChildWindow->ImplGetWindowImpl()->mpSysObj)->windowHandle(); +} diff --git a/vcl/qt5/Qt5Painter.cxx b/vcl/qt5/Qt5Painter.cxx new file mode 100644 index 000000000..06eeb2895 --- /dev/null +++ b/vcl/qt5/Qt5Painter.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +Qt5Painter::Qt5Painter(Qt5Graphics& rGraphics, bool bPrepareBrush, sal_uInt8 nTransparency) + : m_rGraphics(rGraphics) +{ + if (rGraphics.m_pQImage) + begin(rGraphics.m_pQImage); + else + { + assert(rGraphics.m_pFrame); + begin(rGraphics.m_pFrame->GetQWidget()); + } + if (!rGraphics.m_aClipPath.isEmpty()) + setClipPath(rGraphics.m_aClipPath); + else + setClipRegion(rGraphics.m_aClipRegion); + if (SALCOLOR_NONE != rGraphics.m_aLineColor) + { + QColor aColor = toQColor(rGraphics.m_aLineColor); + aColor.setAlpha(nTransparency); + setPen(aColor); + } + else + setPen(Qt::NoPen); + if (bPrepareBrush && SALCOLOR_NONE != rGraphics.m_aFillColor) + { + QColor aColor = toQColor(rGraphics.m_aFillColor); + aColor.setAlpha(nTransparency); + setBrush(aColor); + } + setCompositionMode(rGraphics.m_eCompositionMode); +} diff --git a/vcl/qt5/Qt5Printer.cxx b/vcl/qt5/Qt5Printer.cxx new file mode 100644 index 000000000..16a6a1115 --- /dev/null +++ b/vcl/qt5/Qt5Printer.cxx @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +Qt5Printer::Qt5Printer(SalInfoPrinter* pInfoPrinter) + : PspSalPrinter(pInfoPrinter) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpGraphics.cxx b/vcl/qt5/Qt5SvpGraphics.cxx new file mode 100644 index 000000000..8885b9cb5 --- /dev/null +++ b/vcl/qt5/Qt5SvpGraphics.cxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +Qt5SvpGraphics::Qt5SvpGraphics(Qt5Frame* pFrame) + : SvpSalGraphics() + , m_pFrame(pFrame) +{ + if (!Qt5Data::noNativeControls()) + m_pWidgetDraw.reset(new Qt5Graphics_Controls(*this)); + if (m_pFrame) + setDevicePixelRatioF(m_pFrame->devicePixelRatioF()); +} + +Qt5SvpGraphics::~Qt5SvpGraphics() {} + +void Qt5SvpGraphics::updateQWidget() const +{ + if (!m_pFrame) + return; + QWidget* pQWidget = m_pFrame->GetQWidget(); + if (pQWidget) + pQWidget->update(pQWidget->rect()); +} + +#if ENABLE_CAIRO_CANVAS + +bool Qt5SvpGraphics::SupportsCairo() const { return true; } + +cairo::SurfaceSharedPtr +Qt5SvpGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const +{ + return std::make_shared(rSurface); +} + +cairo::SurfaceSharedPtr Qt5SvpGraphics::CreateSurface(const OutputDevice& /*rRefDevice*/, int x, + int y, int width, int height) const +{ + return std::make_shared(this, x, y, width, height); +} + +#endif + +static void QImage2BitmapBuffer(QImage& rImg, BitmapBuffer& rBuf) +{ + assert(rImg.width()); + assert(rImg.height()); + + rBuf.mnWidth = rImg.width(); + rBuf.mnHeight = rImg.height(); + rBuf.mnBitCount = getFormatBits(rImg.format()); + rBuf.mpBits = rImg.bits(); + rBuf.mnScanlineSize = rImg.bytesPerLine(); +} + +void Qt5SvpGraphics::handleDamage(const tools::Rectangle& rDamagedRegion) +{ + assert(m_pWidgetDraw); + assert(dynamic_cast(m_pWidgetDraw.get())); + assert(!rDamagedRegion.IsEmpty()); + + QImage* pImage = static_cast(m_pWidgetDraw.get())->getImage(); + assert(pImage); + if (pImage->width() == 0 || pImage->height() == 0) + return; + + BitmapBuffer aBuffer; + QImage2BitmapBuffer(*pImage, aBuffer); + SalTwoRect aTR(0, 0, pImage->width(), pImage->height(), rDamagedRegion.getX(), + rDamagedRegion.getY(), rDamagedRegion.GetWidth(), rDamagedRegion.GetHeight()); + drawBitmap(aTR, &aBuffer, CAIRO_OPERATOR_OVER); +} + +void Qt5SvpGraphics::GetResolution(sal_Int32& rDPIX, sal_Int32& rDPIY) +{ + char* pForceDpi; + if ((pForceDpi = getenv("SAL_FORCEDPI"))) + { + OString sForceDPI(pForceDpi); + rDPIX = rDPIY = sForceDPI.toInt32(); + return; + } + + if (!m_pFrame || !m_pFrame->GetQWidget()->window()->windowHandle()) + return; + + QScreen* pScreen = m_pFrame->GetQWidget()->window()->windowHandle()->screen(); + rDPIX = pScreen->logicalDotsPerInchX() * pScreen->devicePixelRatio() + 0.5; + rDPIY = pScreen->logicalDotsPerInchY() * pScreen->devicePixelRatio() + 0.5; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpSurface.cxx b/vcl/qt5/Qt5SvpSurface.cxx new file mode 100644 index 000000000..4bab42997 --- /dev/null +++ b/vcl/qt5/Qt5SvpSurface.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +namespace +{ +Size get_surface_size(cairo_surface_t* surface) +{ + cairo_t* cr = cairo_create(surface); + double x1, x2, y1, y2; + cairo_clip_extents(cr, &x1, &y1, &x2, &y2); + cairo_destroy(cr); + return Size(x2 - x1, y2 - y1); +} +} + +namespace cairo +{ +Qt5SvpSurface::Qt5SvpSurface(const CairoSurfaceSharedPtr& pSurface) + : m_pGraphics(nullptr) + , m_pCairoContext(nullptr) + , m_pSurface(pSurface) +{ +} + +Qt5SvpSurface::Qt5SvpSurface(const Qt5SvpGraphics* pGraphics, int x, int y, int width, int height) + : m_pGraphics(pGraphics) + , m_pCairoContext(pGraphics->getCairoContext(false)) +{ + cairo_surface_t* surface = cairo_get_target(m_pCairoContext); + m_pSurface.reset(cairo_surface_create_for_rectangle(surface, x, y, width, height), + &cairo_surface_destroy); +} + +Qt5SvpSurface::~Qt5SvpSurface() +{ + if (m_pCairoContext) + cairo_destroy(m_pCairoContext); +} + +CairoSharedPtr Qt5SvpSurface::getCairo() const +{ + return CairoSharedPtr(cairo_create(m_pSurface.get()), &cairo_destroy); +} + +SurfaceSharedPtr Qt5SvpSurface::getSimilar(int cairo_content_type, int width, int height) const +{ + return std::make_shared(CairoSurfaceSharedPtr( + cairo_surface_create_similar( + m_pSurface.get(), static_cast(cairo_content_type), width, height), + &cairo_surface_destroy)); +} + +void Qt5SvpSurface::flush() const +{ + cairo_surface_flush(m_pSurface.get()); + if (m_pGraphics) + m_pGraphics->updateQWidget(); +} + +VclPtr Qt5SvpSurface::createVirtualDevice() const +{ + SystemGraphicsData aSystemGraphicsData; + + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.pSurface = m_pSurface.get(); + + return VclPtr::Create(aSystemGraphicsData, get_surface_size(m_pSurface.get()), + DeviceFormat::DEFAULT); +} + +} // namespace cairo + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5SvpVirtualDevice.hxx b/vcl/qt5/Qt5SvpVirtualDevice.hxx new file mode 100644 index 000000000..0eb4ed26e --- /dev/null +++ b/vcl/qt5/Qt5SvpVirtualDevice.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +class VCL_DLLPUBLIC Qt5SvpVirtualDevice : public SvpSalVirtualDevice +{ +public: + Qt5SvpVirtualDevice(DeviceFormat eFormat, cairo_surface_t* pRefSurface, + cairo_surface_t* pPreExistingTarget) + : SvpSalVirtualDevice(eFormat, pRefSurface, pPreExistingTarget) + { + } + + SalGraphics* AcquireGraphics() override { return AddGraphics(new Qt5SvpGraphics(nullptr)); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5System.cxx b/vcl/qt5/Qt5System.cxx new file mode 100644 index 000000000..d769f7118 --- /dev/null +++ b/vcl/qt5/Qt5System.cxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include +#include + +unsigned int Qt5System::GetDisplayScreenCount() +{ + SAL_WNODEPRECATED_DECLARATIONS_PUSH + return QApplication::desktop()->screenCount(); + SAL_WNODEPRECATED_DECLARATIONS_POP +} + +tools::Rectangle Qt5System::GetDisplayScreenPosSizePixel(unsigned int nScreen) +{ + SAL_WNODEPRECATED_DECLARATIONS_PUSH + QRect qRect = QApplication::desktop()->screenGeometry(nScreen); + SAL_WNODEPRECATED_DECLARATIONS_POP + return toRectangle(scaledQRect(qRect, qApp->devicePixelRatio())); +} + +int Qt5System::ShowNativeDialog(const OUString&, const OUString&, const std::vector&) +{ + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Timer.cxx b/vcl/qt5/Qt5Timer.cxx new file mode 100644 index 000000000..bbc2800e8 --- /dev/null +++ b/vcl/qt5/Qt5Timer.cxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include +#include + +Qt5Timer::Qt5Timer() +{ + m_aTimer.setSingleShot(true); + m_aTimer.setTimerType(Qt::PreciseTimer); + connect(&m_aTimer, SIGNAL(timeout()), this, SLOT(timeoutActivated())); + connect(this, SIGNAL(startTimerSignal(int)), this, SLOT(startTimer(int))); + connect(this, SIGNAL(stopTimerSignal()), this, SLOT(stopTimer())); +} + +void Qt5Timer::timeoutActivated() +{ + SolarMutexGuard aGuard; + CallCallback(); +} + +void Qt5Timer::startTimer(int nMS) { m_aTimer.start(nMS); } + +void Qt5Timer::Start(sal_uInt64 nMS) { Q_EMIT startTimerSignal(nMS); } + +void Qt5Timer::stopTimer() { m_aTimer.stop(); } + +void Qt5Timer::Stop() { Q_EMIT stopTimerSignal(); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Tools.cxx b/vcl/qt5/Qt5Tools.cxx new file mode 100644 index 000000000..667a5af6b --- /dev/null +++ b/vcl/qt5/Qt5Tools.cxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include +#include +#include + +#include + +void CairoDeleter::operator()(cairo_surface_t* pSurface) const { cairo_surface_destroy(pSurface); } + +sal_uInt16 GetKeyModCode(Qt::KeyboardModifiers eKeyModifiers) +{ + sal_uInt16 nCode = 0; + if (eKeyModifiers & Qt::ShiftModifier) + nCode |= KEY_SHIFT; + if (eKeyModifiers & Qt::ControlModifier) + nCode |= KEY_MOD1; + if (eKeyModifiers & Qt::AltModifier) + nCode |= KEY_MOD2; + if (eKeyModifiers & Qt::MetaModifier) + nCode |= KEY_MOD3; + return nCode; +} + +sal_uInt16 GetMouseModCode(Qt::MouseButtons eButtons) +{ + sal_uInt16 nCode = 0; + if (eButtons & Qt::LeftButton) + nCode |= MOUSE_LEFT; + if (eButtons & Qt::MidButton) + nCode |= MOUSE_MIDDLE; + if (eButtons & Qt::RightButton) + nCode |= MOUSE_RIGHT; + return nCode; +} + +Qt::DropActions toQtDropActions(sal_Int8 dragOperation) +{ + Qt::DropActions eRet = Qt::IgnoreAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eRet |= Qt::CopyAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eRet |= Qt::MoveAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eRet |= Qt::LinkAction; + return eRet; +} + +sal_Int8 toVclDropActions(Qt::DropActions dragOperation) +{ + sal_Int8 nRet(0); + if (dragOperation & Qt::CopyAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_COPY; + if (dragOperation & Qt::MoveAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + if (dragOperation & Qt::LinkAction) + nRet |= css::datatransfer::dnd::DNDConstants::ACTION_LINK; + return nRet; +} + +sal_Int8 toVclDropAction(Qt::DropAction dragOperation) +{ + sal_Int8 nRet(0); + if (dragOperation == Qt::CopyAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_COPY; + else if (dragOperation == Qt::MoveAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_MOVE; + else if (dragOperation == Qt::LinkAction) + nRet = css::datatransfer::dnd::DNDConstants::ACTION_LINK; + return nRet; +} + +Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation) +{ + Qt::DropAction eAct = Qt::IgnoreAction; + if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_MOVE) + eAct = Qt::MoveAction; + else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_COPY) + eAct = Qt::CopyAction; + else if (dragOperation & css::datatransfer::dnd::DNDConstants::ACTION_LINK) + eAct = Qt::LinkAction; + return eAct; +} + +QImage toQImage(const Image& rImage) +{ + QImage aImage; + + if (!!rImage) + { + SvMemoryStream aMemStm; + vcl::PNGWriter aWriter(rImage.GetBitmapEx()); + aWriter.Write(aMemStm); + aImage.loadFromData(static_cast(aMemStm.GetData()), aMemStm.TellEnd()); + } + + return aImage; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Transferable.cxx b/vcl/qt5/Qt5Transferable.cxx new file mode 100644 index 000000000..2e0deef9b --- /dev/null +++ b/vcl/qt5/Qt5Transferable.cxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include + +#include +#include + +#include + +#include +#include + +#include + +static bool lcl_textMimeInfo(const OUString& rMimeString, bool& bHaveNoCharset, bool& bHaveUTF16, + bool& bHaveUTF8) +{ + sal_Int32 nIndex = 0; + if (rMimeString.getToken(0, ';', nIndex) == "text/plain") + { + OUString aToken(rMimeString.getToken(0, ';', nIndex)); + if (aToken == "charset=utf-16") + bHaveUTF16 = true; + else if (aToken == "charset=utf-8") + bHaveUTF8 = true; + else if (aToken.isEmpty()) + bHaveNoCharset = true; + else // we just handle UTF-16 and UTF-8, everything else is "bytes" + return false; + return true; + } + return false; +} + +Qt5Transferable::Qt5Transferable(const QMimeData* pMimeData) + : m_pMimeData(pMimeData) + , m_bConvertFromLocale(false) +{ + assert(pMimeData); +} + +css::uno::Sequence SAL_CALL Qt5Transferable::getTransferDataFlavors() +{ + // it's just filled once, ever, so just try to get it without locking first + if (m_aMimeTypeSeq.hasElements()) + return m_aMimeTypeSeq; + + // better safe then sorry; preventing broken usage + // DnD should not be shared and Clipboard access runs in the GUI thread + osl::MutexGuard aGuard(m_aMutex); + if (m_aMimeTypeSeq.hasElements()) + return m_aMimeTypeSeq; + + QStringList aFormatList(m_pMimeData->formats()); + // we might add the UTF-16 mime text variant later + const int nMimeTypeSeqSize = aFormatList.size() + 1; + bool bHaveNoCharset = false, bHaveUTF16 = false; + css::uno::Sequence aMimeTypeSeq(nMimeTypeSeqSize); + + css::datatransfer::DataFlavor aFlavor; + int nMimeTypeCount = 0; + + for (const QString& rMimeType : aFormatList) + { + // filter out non-MIME types such as TARGETS, MULTIPLE, TIMESTAMP + if (rMimeType.indexOf('/') == -1) + continue; + + // gtk3 thinks it is not well defined - skip too + if (rMimeType == QStringLiteral("text/plain;charset=unicode")) + continue; + + // LO doesn't like 'text/plain', so we have to provide UTF-16 + bool bIsNoCharset = false, bIsUTF16 = false, bIsUTF8 = false; + if (lcl_textMimeInfo(toOUString(rMimeType), bIsNoCharset, bIsUTF16, bIsUTF8)) + { + bHaveNoCharset |= bIsNoCharset; + bHaveUTF16 |= bIsUTF16; + if (bIsUTF16) + aFlavor.DataType = cppu::UnoType::get(); + else + aFlavor.DataType = cppu::UnoType>::get(); + } + else + aFlavor.DataType = cppu::UnoType>::get(); + + aFlavor.MimeType = toOUString(rMimeType); + assert(nMimeTypeCount < nMimeTypeSeqSize); + aMimeTypeSeq[nMimeTypeCount] = aFlavor; + nMimeTypeCount++; + } + + m_bConvertFromLocale = bHaveNoCharset && !bHaveUTF16; + if (m_bConvertFromLocale) + { + aFlavor.MimeType = "text/plain;charset=utf-16"; + aFlavor.DataType = cppu::UnoType::get(); + assert(nMimeTypeCount < nMimeTypeSeqSize); + aMimeTypeSeq[nMimeTypeCount] = aFlavor; + nMimeTypeCount++; + } + + aMimeTypeSeq.realloc(nMimeTypeCount); + + m_aMimeTypeSeq = aMimeTypeSeq; + return m_aMimeTypeSeq; +} + +sal_Bool SAL_CALL +Qt5Transferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) +{ + const auto aSeq = getTransferDataFlavors(); + return std::any_of(aSeq.begin(), aSeq.end(), [&](const css::datatransfer::DataFlavor& aFlavor) { + return rFlavor.MimeType == aFlavor.MimeType; + }); +} + +css::uno::Any SAL_CALL +Qt5Transferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) +{ + css::uno::Any aAny; + if (!isDataFlavorSupported(rFlavor)) + return aAny; + + if (rFlavor.MimeType == "text/plain;charset=utf-16") + { + OUString aString; + if (m_bConvertFromLocale) + { + QByteArray aByteData(m_pMimeData->data(QStringLiteral("text/plain"))); + aString = OUString(reinterpret_cast(aByteData.data()), aByteData.size(), + osl_getThreadTextEncoding()); + } + else + { + QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); + aString = OUString(reinterpret_cast(aByteData.data()), + aByteData.size() / 2); + } + aAny <<= aString; + } + else + { + QByteArray aByteData(m_pMimeData->data(toQString(rFlavor.MimeType))); + css::uno::Sequence aSeq(reinterpret_cast(aByteData.data()), + aByteData.size()); + aAny <<= aSeq; + } + + return aAny; +} + +Qt5ClipboardTransferable::Qt5ClipboardTransferable(const QClipboard::Mode aMode, + const QMimeData* pMimeData) + : Qt5Transferable(pMimeData) + , m_aMode(aMode) +{ +} + +bool Qt5ClipboardTransferable::hasInFlightChanged() const +{ + const bool bChanged(mimeData() != QApplication::clipboard()->mimeData(m_aMode)); + SAL_WARN_IF(bChanged, "vcl.qt5", + "In flight clipboard change detected - broken clipboard read!"); + return bChanged; +} + +css::uno::Any SAL_CALL +Qt5ClipboardTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor) +{ + css::uno::Any aAny; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + aAny = Qt5Transferable::getTransferData(rFlavor); + }); + return aAny; +} + +css::uno::Sequence + SAL_CALL Qt5ClipboardTransferable::getTransferDataFlavors() +{ + css::uno::Sequence aSeq; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + aSeq = Qt5Transferable::getTransferDataFlavors(); + }); + return aSeq; +} + +sal_Bool SAL_CALL +Qt5ClipboardTransferable::isDataFlavorSupported(const css::datatransfer::DataFlavor& rFlavor) +{ + bool bIsSupported = false; + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + SolarMutexGuard g; + pSalInst->RunInMainThread([&, this]() { + if (!hasInFlightChanged()) + bIsSupported = Qt5Transferable::isDataFlavorSupported(rFlavor); + }); + return bIsSupported; +} + +Qt5MimeData::Qt5MimeData(const css::uno::Reference& xTrans) + : m_aContents(xTrans) + , m_bHaveNoCharset(false) + , m_bHaveUTF8(false) +{ + assert(xTrans.is()); +} + +bool Qt5MimeData::deepCopy(QMimeData** const pMimeCopy) const +{ + if (!pMimeCopy) + return false; + + QMimeData* pMimeData = new QMimeData(); + for (QString& format : formats()) + { + QByteArray aData = data(format); + // Checking for custom MIME types + if (format.startsWith("application/x-qt")) + { + // Retrieving true format name + int indexBegin = format.indexOf('"') + 1; + int indexEnd = format.indexOf('"', indexBegin); + format = format.mid(indexBegin, indexEnd - indexBegin); + } + pMimeData->setData(format, aData); + } + + *pMimeCopy = pMimeData; + return true; +} + +QStringList Qt5MimeData::formats() const +{ + if (!m_aMimeTypeList.isEmpty()) + return m_aMimeTypeList; + + const css::uno::Sequence aFormats + = m_aContents->getTransferDataFlavors(); + QStringList aList; + bool bHaveUTF16 = false; + + for (const auto& rFlavor : aFormats) + { + aList << toQString(rFlavor.MimeType); + lcl_textMimeInfo(rFlavor.MimeType, m_bHaveNoCharset, bHaveUTF16, m_bHaveUTF8); + } + + // we provide a locale encoded and a UTF-8 variant, if missing + if (m_bHaveNoCharset || bHaveUTF16 || m_bHaveUTF8) + { + // if there is a text representation from LO point of view, it'll be UTF-16 + assert(bHaveUTF16); + if (!m_bHaveUTF8) + aList << QStringLiteral("text/plain;charset=utf-8"); + if (!m_bHaveNoCharset) + aList << QStringLiteral("text/plain"); + } + + m_aMimeTypeList = aList; + return m_aMimeTypeList; +} + +QVariant Qt5MimeData::retrieveData(const QString& mimeType, QVariant::Type) const +{ + if (!hasFormat(mimeType)) + return QVariant(); + + css::datatransfer::DataFlavor aFlavor; + aFlavor.MimeType = toOUString(mimeType); + aFlavor.DataType = cppu::UnoType>::get(); + + bool bWantNoCharset = false, bWantUTF16 = false, bWantUTF8 = false; + if (lcl_textMimeInfo(aFlavor.MimeType, bWantNoCharset, bWantUTF16, bWantUTF8)) + { + if ((bWantNoCharset && !m_bHaveNoCharset) || (bWantUTF8 && !m_bHaveUTF8)) + { + aFlavor.MimeType = "text/plain;charset=utf-16"; + aFlavor.DataType = cppu::UnoType::get(); + } + else if (bWantUTF16) + aFlavor.DataType = cppu::UnoType::get(); + } + + css::uno::Any aValue; + + try + { + // tdf#129809 take a reference in case m_aContents is replaced during this call + css::uno::Reference xCurrentContents( + m_aContents); + aValue = xCurrentContents->getTransferData(aFlavor); + } + catch (...) + { + } + + QByteArray aByteArray; + if (aValue.getValueTypeClass() == css::uno::TypeClass_STRING) + { + OUString aString; + aValue >>= aString; + + if (bWantUTF8) + { + OString aUTF8String(OUStringToOString(aString, RTL_TEXTENCODING_UTF8)); + aByteArray = QByteArray(reinterpret_cast(aUTF8String.getStr()), + aUTF8String.getLength()); + } + else if (bWantNoCharset) + { + OString aLocaleString(OUStringToOString(aString, osl_getThreadTextEncoding())); + aByteArray = QByteArray(reinterpret_cast(aLocaleString.getStr()), + aLocaleString.getLength()); + } + else + return QVariant(toQString(aString)); + } + else + { + css::uno::Sequence aData; + aValue >>= aData; + aByteArray + = QByteArray(reinterpret_cast(aData.getConstArray()), aData.getLength()); + } + return QVariant::fromValue(aByteArray); +} + +bool Qt5MimeData::hasFormat(const QString& mimeType) const { return formats().contains(mimeType); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5VirtualDevice.cxx b/vcl/qt5/Qt5VirtualDevice.cxx new file mode 100644 index 000000000..f1c7d9606 --- /dev/null +++ b/vcl/qt5/Qt5VirtualDevice.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include + +Qt5VirtualDevice::Qt5VirtualDevice(DeviceFormat eFormat, double fScale) + : m_eFormat(eFormat) + , m_fScale(fScale) +{ +} + +SalGraphics* Qt5VirtualDevice::AcquireGraphics() +{ + assert(m_pImage); + Qt5Graphics* pGraphics = new Qt5Graphics(m_pImage.get()); + m_aGraphics.push_back(pGraphics); + return pGraphics; +} + +void Qt5VirtualDevice::ReleaseGraphics(SalGraphics* pGraphics) +{ + m_aGraphics.remove(dynamic_cast(pGraphics)); + delete pGraphics; +} + +bool Qt5VirtualDevice::SetSize(long nNewDX, long nNewDY) +{ + return SetSizeUsingBuffer(nNewDX, nNewDY, nullptr); +} + +bool Qt5VirtualDevice::SetSizeUsingBuffer(long nNewDX, long nNewDY, sal_uInt8* pBuffer) +{ + if (nNewDX == 0) + nNewDX = 1; + if (nNewDY == 0) + nNewDY = 1; + + if (m_pImage && m_aFrameSize.width() == nNewDX && m_aFrameSize.height() == nNewDY) + return true; + + m_aFrameSize = QSize(nNewDX, nNewDY); + + nNewDX *= m_fScale; + nNewDY *= m_fScale; + + if (m_eFormat == DeviceFormat::BITMASK) + { + m_pImage.reset(new QImage(nNewDX, nNewDY, QImage::Format_Mono)); + } + else + { + if (pBuffer) + m_pImage.reset(new QImage(pBuffer, nNewDX, nNewDY, Qt5_DefaultFormat32)); + else + m_pImage.reset(new QImage(nNewDX, nNewDY, Qt5_DefaultFormat32)); + } + + m_pImage->fill(Qt::transparent); + m_pImage->setDevicePixelRatio(m_fScale); + + // update device in existing graphics + for (auto pQt5Graph : m_aGraphics) + pQt5Graph->ChangeQImage(m_pImage.get()); + + return true; +} + +long Qt5VirtualDevice::GetWidth() const { return m_pImage ? m_aFrameSize.width() : 0; } + +long Qt5VirtualDevice::GetHeight() const { return m_pImage ? m_aFrameSize.height() : 0; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5Widget.cxx b/vcl/qt5/Qt5Widget.cxx new file mode 100644 index 000000000..0ef305f42 --- /dev/null +++ b/vcl/qt5/Qt5Widget.cxx @@ -0,0 +1,740 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace com::sun::star; + +void Qt5Widget::paintEvent(QPaintEvent* pEvent) +{ + QPainter p(this); + if (!m_rFrame.m_bNullRegion) + p.setClipRegion(m_rFrame.m_aRegion); + + QImage aImage; + if (m_rFrame.m_bUseCairo) + { + cairo_surface_t* pSurface = m_rFrame.m_pSurface.get(); + cairo_surface_flush(pSurface); + + aImage = QImage(cairo_image_surface_get_data(pSurface), + cairo_image_surface_get_width(pSurface), + cairo_image_surface_get_height(pSurface), Qt5_DefaultFormat32); + } + else + aImage = *m_rFrame.m_pQImage; + + const qreal fRatio = m_rFrame.devicePixelRatioF(); + aImage.setDevicePixelRatio(fRatio); + QRectF source(pEvent->rect().topLeft() * fRatio, pEvent->rect().size() * fRatio); + p.drawImage(pEvent->rect(), aImage, source); +} + +void Qt5Widget::resizeEvent(QResizeEvent* pEvent) +{ + const qreal fRatio = m_rFrame.devicePixelRatioF(); + const int nWidth = ceil(pEvent->size().width() * fRatio); + const int nHeight = ceil(pEvent->size().height() * fRatio); + + m_rFrame.maGeometry.nWidth = nWidth; + m_rFrame.maGeometry.nHeight = nHeight; + + if (m_rFrame.m_bUseCairo) + { + if (m_rFrame.m_pSvpGraphics) + { + cairo_surface_t* pSurface + = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); + cairo_surface_set_user_data(pSurface, SvpSalGraphics::getDamageKey(), + &m_rFrame.m_aDamageHandler, nullptr); + m_rFrame.m_pSvpGraphics->setSurface(pSurface, basegfx::B2IVector(nWidth, nHeight)); + UniqueCairoSurface old_surface(m_rFrame.m_pSurface.release()); + m_rFrame.m_pSurface.reset(pSurface); + + int min_width = qMin(cairo_image_surface_get_width(old_surface.get()), nWidth); + int min_height = qMin(cairo_image_surface_get_height(old_surface.get()), nHeight); + + SalTwoRect rect(0, 0, min_width, min_height, 0, 0, min_width, min_height); + + m_rFrame.m_pSvpGraphics->copySource(rect, old_surface.get()); + } + } + else + { + QImage* pImage = nullptr; + + if (m_rFrame.m_pQImage) + pImage = new QImage(m_rFrame.m_pQImage->copy(0, 0, nWidth, nHeight)); + else + { + pImage = new QImage(nWidth, nHeight, Qt5_DefaultFormat32); + pImage->fill(Qt::transparent); + } + + m_rFrame.m_pQt5Graphics->ChangeQImage(pImage); + m_rFrame.m_pQImage.reset(pImage); + } + + m_rFrame.CallCallback(SalEvent::Resize, nullptr); +} + +void Qt5Widget::handleMouseButtonEvent(const Qt5Frame& rFrame, const QMouseEvent* pEvent, + const ButtonKeyState eState) +{ + SalMouseEvent aEvent; + switch (pEvent->button()) + { + case Qt::LeftButton: + aEvent.mnButton = MOUSE_LEFT; + break; + case Qt::MidButton: + aEvent.mnButton = MOUSE_MIDDLE; + break; + case Qt::RightButton: + aEvent.mnButton = MOUSE_RIGHT; + break; + default: + return; + } + + const qreal fRatio = rFrame.devicePixelRatioF(); + const Point aPos = toPoint(pEvent->pos() * fRatio); + + aEvent.mnX = QGuiApplication::isLeftToRight() + ? aPos.X() + : round(rFrame.GetQWidget()->width() * fRatio) - aPos.X(); + aEvent.mnY = aPos.Y(); + aEvent.mnTime = pEvent->timestamp(); + aEvent.mnCode = GetKeyModCode(pEvent->modifiers()) | GetMouseModCode(pEvent->buttons()); + + SalEvent nEventType; + if (eState == ButtonKeyState::Pressed) + nEventType = SalEvent::MouseButtonDown; + else + nEventType = SalEvent::MouseButtonUp; + rFrame.CallCallback(nEventType, &aEvent); +} + +void Qt5Widget::mousePressEvent(QMouseEvent* pEvent) { handleMousePressEvent(m_rFrame, pEvent); } + +void Qt5Widget::mouseReleaseEvent(QMouseEvent* pEvent) +{ + handleMouseReleaseEvent(m_rFrame, pEvent); +} + +void Qt5Widget::mouseMoveEvent(QMouseEvent* pEvent) +{ + const qreal fRatio = m_rFrame.devicePixelRatioF(); + const Point aPos = toPoint(pEvent->pos() * fRatio); + + SalMouseEvent aEvent; + aEvent.mnX = QGuiApplication::isLeftToRight() ? aPos.X() : round(width() * fRatio) - aPos.X(); + aEvent.mnY = aPos.Y(); + aEvent.mnTime = pEvent->timestamp(); + aEvent.mnCode = GetKeyModCode(pEvent->modifiers()) | GetMouseModCode(pEvent->buttons()); + aEvent.mnButton = 0; + + m_rFrame.CallCallback(SalEvent::MouseMove, &aEvent); + pEvent->accept(); +} + +void Qt5Widget::wheelEvent(QWheelEvent* pEvent) +{ + const Point aPos = toPoint(pEvent->pos() * m_rFrame.devicePixelRatioF()); + + SalWheelMouseEvent aEvent; + aEvent.mnX = QGuiApplication::isLeftToRight() + ? aPos.X() + : round(width() * m_rFrame.devicePixelRatioF()) - aPos.X(); + aEvent.mnY = aPos.Y(); + aEvent.mnTime = pEvent->timestamp(); + aEvent.mnCode = GetKeyModCode(pEvent->modifiers()) | GetMouseModCode(pEvent->buttons()); + + // mouse wheel ticks are 120, which we map to 3 lines. + // we have to accumulate for touch scroll to keep track of the absolute delta. + + int nDelta = pEvent->angleDelta().y(), lines; + aEvent.mbHorz = nDelta == 0; + if (aEvent.mbHorz) + { + nDelta = (QGuiApplication::isLeftToRight() ? 1 : -1) * pEvent->angleDelta().x(); + if (!nDelta) + return; + + m_nDeltaX += nDelta; + lines = m_nDeltaX / 40; + m_nDeltaX = m_nDeltaX % 40; + } + else + { + m_nDeltaY += nDelta; + lines = m_nDeltaY / 40; + m_nDeltaY = m_nDeltaY % 40; + } + + aEvent.mnDelta = nDelta; + aEvent.mnNotchDelta = nDelta < 0 ? -1 : 1; + aEvent.mnScrollLines = std::abs(lines); + + m_rFrame.CallCallback(SalEvent::WheelMouse, &aEvent); + pEvent->accept(); +} + +void Qt5Widget::dragEnterEvent(QDragEnterEvent* event) +{ + if (dynamic_cast(event->mimeData())) + event->accept(); + else + event->acceptProposedAction(); +} + +// also called when a drop is rejected +void Qt5Widget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); } + +void Qt5Widget::dragMoveEvent(QDragMoveEvent* pEvent) { m_rFrame.handleDragMove(pEvent); } + +void Qt5Widget::dropEvent(QDropEvent* pEvent) { m_rFrame.handleDrop(pEvent); } + +void Qt5Widget::moveEvent(QMoveEvent* pEvent) +{ + if (m_rFrame.m_pTopLevel) + return; + + const Point aPos = toPoint(pEvent->pos() * m_rFrame.devicePixelRatioF()); + m_rFrame.maGeometry.nX = aPos.X(); + m_rFrame.maGeometry.nY = aPos.Y(); + m_rFrame.CallCallback(SalEvent::Move, nullptr); +} + +void Qt5Widget::showEvent(QShowEvent*) +{ + QSize aSize(m_rFrame.GetQWidget()->size() * m_rFrame.devicePixelRatioF()); + // forcing an immediate update somehow interferes with the hide + show + // sequence from Qt5Frame::SetModal, if the frame was already set visible, + // resulting in a hidden / unmapped window + SalPaintEvent aPaintEvt(0, 0, aSize.width(), aSize.height()); + m_rFrame.CallCallback(SalEvent::Paint, &aPaintEvt); +} + +void Qt5Widget::closeEvent(QCloseEvent* /*pEvent*/) +{ + m_rFrame.CallCallback(SalEvent::Close, nullptr); +} + +static sal_uInt16 GetKeyCode(int keyval, Qt::KeyboardModifiers modifiers) +{ + sal_uInt16 nCode = 0; + if (keyval >= Qt::Key_0 && keyval <= Qt::Key_9) + nCode = KEY_0 + (keyval - Qt::Key_0); + else if (keyval >= Qt::Key_A && keyval <= Qt::Key_Z) + nCode = KEY_A + (keyval - Qt::Key_A); + else if (keyval >= Qt::Key_F1 && keyval <= Qt::Key_F26) + nCode = KEY_F1 + (keyval - Qt::Key_F1); + else if (modifiers.testFlag(Qt::KeypadModifier) + && (keyval == Qt::Key_Period || keyval == Qt::Key_Comma)) + // Qt doesn't use a special keyval for decimal separator ("," or ".") + // on numerical keypad, but sets Qt::KeypadModifier in addition + nCode = KEY_DECIMAL; + else + { + switch (keyval) + { + case Qt::Key_Down: + nCode = KEY_DOWN; + break; + case Qt::Key_Up: + nCode = KEY_UP; + break; + case Qt::Key_Left: + nCode = KEY_LEFT; + break; + case Qt::Key_Right: + nCode = KEY_RIGHT; + break; + case Qt::Key_Home: + nCode = KEY_HOME; + break; + case Qt::Key_End: + nCode = KEY_END; + break; + case Qt::Key_PageUp: + nCode = KEY_PAGEUP; + break; + case Qt::Key_PageDown: + nCode = KEY_PAGEDOWN; + break; + case Qt::Key_Return: + case Qt::Key_Enter: + nCode = KEY_RETURN; + break; + case Qt::Key_Escape: + nCode = KEY_ESCAPE; + break; + case Qt::Key_Tab: + // oddly enough, Qt doesn't send Shift-Tab event as 'Tab key pressed with Shift + // modifier' but as 'Backtab key pressed' (while its modifier bits are still + // set to Shift) -- so let's map both Key_Tab and Key_Backtab to VCL's KEY_TAB + case Qt::Key_Backtab: + nCode = KEY_TAB; + break; + case Qt::Key_Backspace: + nCode = KEY_BACKSPACE; + break; + case Qt::Key_Space: + nCode = KEY_SPACE; + break; + case Qt::Key_Insert: + nCode = KEY_INSERT; + break; + case Qt::Key_Delete: + nCode = KEY_DELETE; + break; + case Qt::Key_Plus: + nCode = KEY_ADD; + break; + case Qt::Key_Minus: + nCode = KEY_SUBTRACT; + break; + case Qt::Key_Asterisk: + nCode = KEY_MULTIPLY; + break; + case Qt::Key_Slash: + nCode = KEY_DIVIDE; + break; + case Qt::Key_Period: + nCode = KEY_POINT; + break; + case Qt::Key_Comma: + nCode = KEY_COMMA; + break; + case Qt::Key_Less: + nCode = KEY_LESS; + break; + case Qt::Key_Greater: + nCode = KEY_GREATER; + break; + case Qt::Key_Equal: + nCode = KEY_EQUAL; + break; + case Qt::Key_Find: + nCode = KEY_FIND; + break; + case Qt::Key_Menu: + nCode = KEY_CONTEXTMENU; + break; + case Qt::Key_Help: + nCode = KEY_HELP; + break; + case Qt::Key_Undo: + nCode = KEY_UNDO; + break; + case Qt::Key_Redo: + nCode = KEY_REPEAT; + break; + case Qt::Key_Cancel: + nCode = KEY_F11; + break; + case Qt::Key_AsciiTilde: + nCode = KEY_TILDE; + break; + case Qt::Key_QuoteLeft: + nCode = KEY_QUOTELEFT; + break; + case Qt::Key_BracketLeft: + nCode = KEY_BRACKETLEFT; + break; + case Qt::Key_BracketRight: + nCode = KEY_BRACKETRIGHT; + break; + case Qt::Key_Semicolon: + nCode = KEY_SEMICOLON; + break; + case Qt::Key_Copy: + nCode = KEY_COPY; + break; + case Qt::Key_Cut: + nCode = KEY_CUT; + break; + case Qt::Key_Open: + nCode = KEY_OPEN; + break; + case Qt::Key_Paste: + nCode = KEY_PASTE; + break; + } + } + + return nCode; +} + +void Qt5Widget::commitText(Qt5Frame& rFrame, const QString& aText) +{ + SalExtTextInputEvent aInputEvent; + aInputEvent.mpTextAttr = nullptr; + aInputEvent.mnCursorFlags = 0; + aInputEvent.maText = toOUString(aText); + aInputEvent.mnCursorPos = aInputEvent.maText.getLength(); + + SolarMutexGuard aGuard; + vcl::DeletionListener aDel(&rFrame); + rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); + if (!aDel.isDeleted()) + rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); +} + +bool Qt5Widget::handleKeyEvent(Qt5Frame& rFrame, const QWidget& rWidget, QKeyEvent* pEvent, + const ButtonKeyState eState) +{ + sal_uInt16 nCode = GetKeyCode(pEvent->key(), pEvent->modifiers()); + if (eState == ButtonKeyState::Pressed && nCode == 0 && pEvent->text().length() > 1 + && rWidget.testAttribute(Qt::WA_InputMethodEnabled)) + { + commitText(rFrame, pEvent->text()); + pEvent->accept(); + return true; + } + + SalKeyEvent aEvent; + aEvent.mnCharCode = (pEvent->text().isEmpty() ? 0 : pEvent->text().at(0).unicode()); + aEvent.mnRepeat = 0; + aEvent.mnCode = nCode; + aEvent.mnCode |= GetKeyModCode(pEvent->modifiers()); + + QGuiApplication::inputMethod()->update(Qt::ImCursorRectangle); + + bool bStopProcessingKey; + if (eState == ButtonKeyState::Pressed) + bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyInput, &aEvent); + else + bStopProcessingKey = rFrame.CallCallback(SalEvent::KeyUp, &aEvent); + if (bStopProcessingKey) + pEvent->accept(); + return bStopProcessingKey; +} + +bool Qt5Widget::handleEvent(Qt5Frame& rFrame, const QWidget& rWidget, QEvent* pEvent) +{ + if (pEvent->type() == QEvent::ShortcutOverride) + { + // ignore non-spontaneous QEvent::ShortcutOverride events, + // since such an extra event is sent e.g. with Orca screen reader enabled, + // so that two events of that kind (the "real one" and a non-spontaneous one) + // would otherwise be processed, resulting in duplicate input as 'handleKeyEvent' + // is called below (s. tdf#122053) + if (!pEvent->spontaneous()) + { + return false; + } + + // Accepted event disables shortcut activation, + // but enables keypress event. + // If event is not accepted and shortcut is successfully activated, + // KeyPress event is omitted. + // + // Instead of processing keyPressEvent, handle ShortcutOverride event, + // and if it's handled - disable the shortcut, it should have been activated. + // Don't process keyPressEvent generated after disabling shortcut since it was handled here. + // If event is not handled, don't accept it and let Qt activate related shortcut. + if (handleKeyEvent(rFrame, rWidget, static_cast(pEvent), + ButtonKeyState::Pressed)) + return true; + } + return false; +} + +bool Qt5Widget::event(QEvent* pEvent) +{ + return handleEvent(m_rFrame, *this, pEvent) || QWidget::event(pEvent); +} + +void Qt5Widget::keyReleaseEvent(QKeyEvent* pEvent) +{ + if (!handleKeyReleaseEvent(m_rFrame, *this, pEvent)) + QWidget::keyReleaseEvent(pEvent); +} + +void Qt5Widget::focusInEvent(QFocusEvent*) { m_rFrame.CallCallback(SalEvent::GetFocus, nullptr); } + +void Qt5Widget::focusOutEvent(QFocusEvent*) +{ + endExtTextInput(); + m_rFrame.CallCallback(SalEvent::LoseFocus, nullptr); +} + +Qt5Widget::Qt5Widget(Qt5Frame& rFrame, Qt::WindowFlags f) + : QWidget(Q_NULLPTR, f) + , m_rFrame(rFrame) + , m_bNonEmptyIMPreeditSeen(false) + , m_nDeltaX(0) + , m_nDeltaY(0) +{ + create(); + setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); +} + +static ExtTextInputAttr lcl_MapUndrelineStyle(QTextCharFormat::UnderlineStyle us) +{ + switch (us) + { + case QTextCharFormat::NoUnderline: + return ExtTextInputAttr::NONE; + case QTextCharFormat::DotLine: + return ExtTextInputAttr::DottedUnderline; + case QTextCharFormat::DashDotDotLine: + case QTextCharFormat::DashDotLine: + return ExtTextInputAttr::DashDotUnderline; + case QTextCharFormat::WaveUnderline: + return ExtTextInputAttr::GrayWaveline; + default: + return ExtTextInputAttr::Underline; + } +} + +void Qt5Widget::inputMethodEvent(QInputMethodEvent* pEvent) +{ + if (!pEvent->commitString().isEmpty()) + commitText(m_rFrame, pEvent->commitString()); + else + { + SalExtTextInputEvent aInputEvent; + aInputEvent.mpTextAttr = nullptr; + aInputEvent.mnCursorFlags = 0; + aInputEvent.maText = toOUString(pEvent->preeditString()); + aInputEvent.mnCursorPos = 0; + + const sal_Int32 nLength = aInputEvent.maText.getLength(); + const QList& rAttrList = pEvent->attributes(); + std::vector aTextAttrs(std::max(sal_Int32(1), nLength), + ExtTextInputAttr::NONE); + aInputEvent.mpTextAttr = aTextAttrs.data(); + + for (int i = 0; i < rAttrList.size(); ++i) + { + const QInputMethodEvent::Attribute& rAttr = rAttrList.at(i); + switch (rAttr.type) + { + case QInputMethodEvent::TextFormat: + { + QTextCharFormat aCharFormat + = qvariant_cast(rAttr.value).toCharFormat(); + if (aCharFormat.isValid()) + { + ExtTextInputAttr aETIP + = lcl_MapUndrelineStyle(aCharFormat.underlineStyle()); + if (aCharFormat.hasProperty(QTextFormat::BackgroundBrush)) + aETIP |= ExtTextInputAttr::Highlight; + if (aCharFormat.fontStrikeOut()) + aETIP |= ExtTextInputAttr::RedText; + for (int j = rAttr.start; j < rAttr.start + rAttr.length; j++) + aTextAttrs[j] = aETIP; + } + break; + } + case QInputMethodEvent::Cursor: + { + aInputEvent.mnCursorPos = rAttr.start; + if (rAttr.length == 0) + aInputEvent.mnCursorFlags |= EXTTEXTINPUT_CURSOR_INVISIBLE; + break; + } + default: + SAL_WARN("vcl.qt5", "Unhandled QInputMethodEvent attribute: " + << static_cast(rAttr.type)); + break; + } + } + + const bool bIsEmpty = aInputEvent.maText.isEmpty(); + if (m_bNonEmptyIMPreeditSeen || !bIsEmpty) + { + SolarMutexGuard aGuard; + vcl::DeletionListener aDel(&m_rFrame); + m_rFrame.CallCallback(SalEvent::ExtTextInput, &aInputEvent); + if (!aDel.isDeleted() && bIsEmpty) + m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); + m_bNonEmptyIMPreeditSeen = !bIsEmpty; + } + } + + pEvent->accept(); +} + +static bool lcl_retrieveSurrounding(sal_Int32& rPosition, sal_Int32& rAnchor, QString* pText, + QString* pSelection) +{ + SolarMutexGuard aGuard; + vcl::Window* pFocusWin = Application::GetFocusWindow(); + if (!pFocusWin) + return false; + + uno::Reference xText; + try + { + uno::Reference xAccessible(pFocusWin->GetAccessible()); + if (xAccessible.is()) + xText = FindFocusedEditableText(xAccessible->getAccessibleContext()); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("vcl.qt5", "Exception in getting input method surrounding text"); + } + + if (xText.is()) + { + rPosition = xText->getCaretPosition(); + if (rPosition != -1) + { + if (pText) + *pText = toQString(xText->getText()); + + sal_Int32 nSelStart = xText->getSelectionStart(); + sal_Int32 nSelEnd = xText->getSelectionEnd(); + if (nSelStart == nSelEnd) + { + rAnchor = rPosition; + } + else + { + if (rPosition == nSelStart) + rAnchor = nSelEnd; + else + rAnchor = nSelStart; + if (pSelection) + *pSelection = toQString(xText->getSelectedText()); + } + return true; + } + } + + return false; +} + +QVariant Qt5Widget::inputMethodQuery(Qt::InputMethodQuery property) const +{ + switch (property) + { + case Qt::ImSurroundingText: + { + QString aText; + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, &aText, nullptr)) + return QVariant(aText); + [[fallthrough]]; + } + case Qt::ImCursorPosition: + { + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) + return QVariant(static_cast(nCursorPos)); + [[fallthrough]]; + } + case Qt::ImCursorRectangle: + { + SalExtTextInputPosEvent aPosEvent; + m_rFrame.CallCallback(SalEvent::ExtTextInputPos, &aPosEvent); + return QVariant( + QRect(aPosEvent.mnX, aPosEvent.mnY, aPosEvent.mnWidth, aPosEvent.mnHeight)); + } + case Qt::ImAnchorPosition: + { + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, nullptr)) + return QVariant(static_cast(nAnchor)); + [[fallthrough]]; + } + case Qt::ImCurrentSelection: + { + QString aSelection; + sal_Int32 nCursorPos, nAnchor; + if (lcl_retrieveSurrounding(nCursorPos, nAnchor, nullptr, &aSelection)) + return QVariant(aSelection); + [[fallthrough]]; + } + default: + return QWidget::inputMethodQuery(property); + } + + return QVariant(); +} + +void Qt5Widget::endExtTextInput() +{ + if (m_bNonEmptyIMPreeditSeen) + { + m_rFrame.CallCallback(SalEvent::EndExtTextInput, nullptr); + m_bNonEmptyIMPreeditSeen = false; + } +} + +void Qt5Widget::changeEvent(QEvent* pEvent) +{ + switch (pEvent->type()) + { + case QEvent::FontChange: + [[fallthrough]]; + case QEvent::PaletteChange: + [[fallthrough]]; + case QEvent::StyleChange: + { + auto* pSalInst(static_cast(GetSalData()->m_pInstance)); + assert(pSalInst); + pSalInst->UpdateStyle(QEvent::FontChange == pEvent->type()); + break; + } + default: + break; + } + QWidget::changeEvent(pEvent); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/Qt5XAccessible.cxx b/vcl/qt5/Qt5XAccessible.cxx new file mode 100644 index 000000000..e9f0804d5 --- /dev/null +++ b/vcl/qt5/Qt5XAccessible.cxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace css::accessibility; +using namespace css::uno; + +Qt5XAccessible::Qt5XAccessible(Reference xAccessible) + : m_xAccessible(xAccessible) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx new file mode 100644 index 000000000..eb67d981f --- /dev/null +++ b/vcl/quartz/ctfonts.cxx @@ -0,0 +1,560 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include + + +#include +#include +#ifdef MACOSX +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +static double toRadian(int nDegree) +{ + return nDegree * (M_PI / 1800.0); +} + +CoreTextStyle::CoreTextStyle(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP) + : LogicalFontInstance(rPFF, rFSP) + , mfFontStretch( 1.0 ) + , mfFontRotation( 0.0 ) + , mbFauxBold(false) + , mpStyleDict( nullptr ) +{ + double fScaledFontHeight = rFSP.mfExactHeight; + + // convert font rotation to radian + mfFontRotation = toRadian(rFSP.mnOrientation); + + // dummy matrix so we can use CGAffineTransformConcat() below + CGAffineTransform aMatrix = CGAffineTransformMakeTranslation(0, 0); + + // handle font stretching if any + if( (rFSP.mnWidth != 0) && (rFSP.mnWidth != rFSP.mnHeight) ) + { + mfFontStretch = float(rFSP.mnWidth) / rFSP.mnHeight; + aMatrix = CGAffineTransformConcat(aMatrix, CGAffineTransformMakeScale(mfFontStretch, 1.0F)); + } + + // create the style object for CoreText font attributes + static const CFIndex nMaxDictSize = 16; // TODO: does this really suffice? + mpStyleDict = CFDictionaryCreateMutable( nullptr, nMaxDictSize, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks ); + + CFBooleanRef pCFVertBool = rFSP.mbVertical ? kCFBooleanTrue : kCFBooleanFalse; + CFDictionarySetValue( mpStyleDict, kCTVerticalFormsAttributeName, pCFVertBool ); + + // fake bold + if ( (rFSP.GetWeight() >= WEIGHT_BOLD) && + ((rPFF.GetWeight() < WEIGHT_SEMIBOLD) && + (rPFF.GetWeight() != WEIGHT_DONTKNOW)) ) + { + mbFauxBold = true; + } + + // fake italic + if (((rFSP.GetItalic() == ITALIC_NORMAL) || + (rFSP.GetItalic() == ITALIC_OBLIQUE)) && + (rPFF.GetItalic() == ITALIC_NONE)) + { + aMatrix = CGAffineTransformConcat(aMatrix, CGAffineTransformMake(1, 0, toRadian(120), 1, 0, 0)); + } + + CTFontDescriptorRef pFontDesc = reinterpret_cast(rPFF.GetFontId()); + CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, &aMatrix ); + CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont ); + CFRelease( pNewCTFont); +} + +CoreTextStyle::~CoreTextStyle() +{ + if( mpStyleDict ) + CFRelease( mpStyleDict ); +} + +void CoreTextStyle::GetFontMetric( ImplFontMetricDataRef const & rxFontMetric ) +{ + // get the matching CoreText font handle + // TODO: is it worth it to cache the CTFontRef in SetFont() and reuse it here? + CTFontRef aCTFontRef = static_cast(CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName )); + + rxFontMetric->ImplCalcLineSpacing(this); + + // 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 + rxFontMetric->SetWidth( lrint( CTFontGetSize( aCTFontRef ) * mfFontStretch) ); + + rxFontMetric->SetMinKashida(GetKashidaWidth()); +} + +bool CoreTextStyle::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const +{ + CGGlyph nCGGlyph = nId; + CTFontRef aCTFontRef = static_cast(CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName )); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.11 kCTFontDefaultOrientation + const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert + SAL_WNODEPRECATED_DECLARATIONS_POP + CGRect aCGRect = CTFontGetBoundingRectsForGlyphs(aCTFontRef, aFontOrientation, &nCGGlyph, nullptr, 1); + + // Apply font rotation to non-vertical glyphs. + if (mfFontRotation && !bVertical) + aCGRect = CGRectApplyAffineTransform(aCGRect, CGAffineTransformMakeRotation(mfFontRotation)); + + long xMin = floor(aCGRect.origin.x); + long yMin = floor(aCGRect.origin.y); + long xMax = ceil(aCGRect.origin.x + aCGRect.size.width); + long yMax = ceil(aCGRect.origin.y + aCGRect.size.height); + rRect = tools::Rectangle(xMin, -yMax, xMax, -yMin); + return true; +} + +namespace { + +// callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline() +struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; }; + +} + +static void MyCGPathApplierFunc( void* pData, const CGPathElement* pElement ) +{ + basegfx::B2DPolygon& rPolygon = static_cast(pData)->maPolygon; + const int nPointCount = rPolygon.count(); + + switch( pElement->type ) + { + case kCGPathElementCloseSubpath: + case kCGPathElementMoveToPoint: + if( nPointCount > 0 ) + { + static_cast(pData)->mpPolyPoly->append( rPolygon ); + rPolygon.clear(); + } + // fall through for kCGPathElementMoveToPoint: + if( pElement->type != kCGPathElementMoveToPoint ) + { + break; + } + [[fallthrough]]; + case kCGPathElementAddLineToPoint: + rPolygon.append( basegfx::B2DPoint( +pElement->points[0].x, -pElement->points[0].y ) ); + break; + + case kCGPathElementAddCurveToPoint: + rPolygon.append( basegfx::B2DPoint( +pElement->points[2].x, -pElement->points[2].y ) ); + rPolygon.setNextControlPoint( nPointCount - 1, + basegfx::B2DPoint( pElement->points[0].x, + -pElement->points[0].y ) ); + rPolygon.setPrevControlPoint( nPointCount + 0, + basegfx::B2DPoint( pElement->points[1].x, + -pElement->points[1].y ) ); + break; + + case kCGPathElementAddQuadCurveToPoint: + { + const basegfx::B2DPoint aStartPt = rPolygon.getB2DPoint( nPointCount-1 ); + const basegfx::B2DPoint aCtrPt1( (aStartPt.getX() + 2 * pElement->points[0].x) / 3.0, + (aStartPt.getY() - 2 * pElement->points[0].y) / 3.0 ); + const basegfx::B2DPoint aCtrPt2( (+2 * pElement->points[0].x + pElement->points[1].x) / 3.0, + (-2 * pElement->points[0].y - pElement->points[1].y) / 3.0 ); + rPolygon.append( basegfx::B2DPoint( +pElement->points[1].x, -pElement->points[1].y ) ); + rPolygon.setNextControlPoint( nPointCount-1, aCtrPt1 ); + rPolygon.setPrevControlPoint( nPointCount+0, aCtrPt2 ); + } + break; + } +} + +bool CoreTextStyle::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rResult, bool) const +{ + rResult.clear(); + + CGGlyph nCGGlyph = nId; + CTFontRef pCTFont = static_cast(CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName )); + + SAL_WNODEPRECATED_DECLARATIONS_PUSH + const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; + SAL_WNODEPRECATED_DECLARATIONS_POP + CGRect aCGRect = CTFontGetBoundingRectsForGlyphs(pCTFont, aFontOrientation, &nCGGlyph, nullptr, 1); + + if (!CGRectIsNull(aCGRect) && CGRectIsEmpty(aCGRect)) + { + // CTFontCreatePathForGlyph returns NULL for blank glyphs, but we want + // to return true for them. + return true; + } + + CGPathRef xPath = CTFontCreatePathForGlyph( pCTFont, nCGGlyph, nullptr ); + if (!xPath) + { + return false; + } + + GgoData aGgoData; + aGgoData.mpPolyPoly = &rResult; + CGPathApply( xPath, static_cast(&aGgoData), MyCGPathApplierFunc ); +#if 0 // TODO: does OSX ensure that the last polygon is always closed? + const CGPathElement aClosingElement = { kCGPathElementCloseSubpath, NULL }; + MyCGPathApplierFunc( (void*)&aGgoData, &aClosingElement ); +#endif + CFRelease( xPath ); + + return true; +} + +static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pUserData) +{ + sal_uLong nLength = 0; + unsigned char* pBuffer = nullptr; + CoreTextFontFace* pFont = static_cast(pUserData); + nLength = pFont->GetFontTable(nTableTag, nullptr); + if (nLength > 0) + { + pBuffer = new unsigned char[nLength]; + pFont->GetFontTable(nTableTag, pBuffer); + } + + hb_blob_t* pBlob = nullptr; + if (pBuffer != nullptr) + pBlob = hb_blob_create(reinterpret_cast(pBuffer), nLength, HB_MEMORY_MODE_READONLY, + pBuffer, [](void* data){ delete[] static_cast(data); }); + return pBlob; +} + +hb_font_t* CoreTextStyle::ImplInitHbFont() +{ + hb_face_t* pHbFace = hb_face_create_for_tables(getFontTable, GetFontFace(), nullptr); + + return InitHbFont(pHbFace); +} + +rtl::Reference CoreTextFontFace::CreateFontInstance(const FontSelectPattern& rFSD) const +{ + return new CoreTextStyle(*this, rFSD); +} + +int CoreTextFontFace::GetFontTable( const char pTagName[5], unsigned char* pResultBuf ) const +{ + SAL_WARN_IF( pTagName[4]!='\0', "vcl", "CoreTextFontFace::GetFontTable with invalid tagname!" ); + + const CTFontTableTag nTagCode = (pTagName[0]<<24) + (pTagName[1]<<16) + (pTagName[2]<<8) + (pTagName[3]<<0); + + return GetFontTable(nTagCode, pResultBuf); +} + +int CoreTextFontFace::GetFontTable(uint32_t nTagCode, unsigned char* pResultBuf ) const +{ + // get the raw table length + CTFontDescriptorRef pFontDesc = reinterpret_cast( GetFontId()); + CTFontRef rCTFont = CTFontCreateWithFontDescriptor( pFontDesc, 0.0, nullptr); + const uint32_t opts( kCTFontTableOptionNoOptions ); + CFDataRef pDataRef = CTFontCopyTable( rCTFont, nTagCode, opts); + CFRelease( rCTFont); + if( !pDataRef) + return 0; + + const CFIndex nByteLength = CFDataGetLength( pDataRef); + + // get the raw table data if requested + if( pResultBuf && (nByteLength > 0)) + { + const CFRange aFullRange = CFRangeMake( 0, nByteLength); + CFDataGetBytes( pDataRef, aFullRange, reinterpret_cast(pResultBuf)); + } + + CFRelease( pDataRef); + + return static_cast(nByteLength); +} + +FontAttributes DevFontFromCTFontDescriptor( CTFontDescriptorRef pFD, bool* bFontEnabled ) +{ + // all CoreText fonts are device fonts that can rotate just fine + FontAttributes rDFA; + rDFA.SetQuality( 0 ); + + // reset the font attributes + rDFA.SetFamilyType( FAMILY_DONTKNOW ); + rDFA.SetPitch( PITCH_VARIABLE ); + rDFA.SetWidthType( WIDTH_NORMAL ); + rDFA.SetWeight( WEIGHT_NORMAL ); + rDFA.SetItalic( ITALIC_NONE ); + rDFA.SetSymbolFlag( false ); + + // get font name +#ifdef MACOSX + CFStringRef pLang = nullptr; + CFStringRef pFamilyName = static_cast( + CTFontDescriptorCopyLocalizedAttribute( pFD, kCTFontFamilyNameAttribute, &pLang )); + + if ( !pLang ) + { + if( pFamilyName ) + { + CFRelease( pFamilyName ); + } + pFamilyName = static_cast(CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute )); + } +#else + // No "Application" on iOS. And it is unclear whether this code + // snippet will actually ever get invoked on iOS anyway. So just + // use the old code that uses a non-localized font name. + CFStringRef pFamilyName = (CFStringRef)CTFontDescriptorCopyAttribute( pFD, kCTFontFamilyNameAttribute ); +#endif + + rDFA.SetFamilyName( GetOUString( pFamilyName ) ); + + // get font style + CFStringRef pStyleName = static_cast(CTFontDescriptorCopyAttribute( pFD, kCTFontStyleNameAttribute )); + rDFA.SetStyleName( GetOUString( pStyleName ) ); + + // get font-enabled status + if( bFontEnabled ) + { + int bEnabled = TRUE; // by default (and when we're on macOS < 10.6) it's "enabled" + CFNumberRef pEnabled = static_cast(CTFontDescriptorCopyAttribute( pFD, kCTFontEnabledAttribute )); + CFNumberGetValue( pEnabled, kCFNumberIntType, &bEnabled ); + *bFontEnabled = bEnabled; + } + + // get font attributes + CFDictionaryRef pAttrDict = static_cast(CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute )); + + if (bFontEnabled && *bFontEnabled) + { + // Ignore font formats not supported. + int nFormat; + CFNumberRef pFormat = static_cast(CTFontDescriptorCopyAttribute(pFD, kCTFontFormatAttribute)); + CFNumberGetValue(pFormat, kCFNumberIntType, &nFormat); + if (nFormat == kCTFontFormatUnrecognized || nFormat == kCTFontFormatPostScript || nFormat == kCTFontFormatBitmap) + { + SAL_INFO("vcl.fonts", "Ignoring font with unsupported format: " << rDFA.GetFamilyName()); + *bFontEnabled = false; + } + CFRelease(pFormat); + } + + // get symbolic trait + // TODO: use other traits such as MonoSpace/Condensed/Expanded or Vertical too + SInt64 nSymbolTrait = 0; + CFNumberRef pSymbolNum = nullptr; + if( CFDictionaryGetValueIfPresent( pAttrDict, kCTFontSymbolicTrait, reinterpret_cast(&pSymbolNum) ) ) + { + CFNumberGetValue( pSymbolNum, kCFNumberSInt64Type, &nSymbolTrait ); + rDFA.SetSymbolFlag( (nSymbolTrait & kCTFontClassMaskTrait) == kCTFontSymbolicClass ); + } + + // get the font weight + double fWeight = 0; + CFNumberRef pWeightNum = static_cast(CFDictionaryGetValue( pAttrDict, kCTFontWeightTrait )); + CFNumberGetValue( pWeightNum, kCFNumberDoubleType, &fWeight ); + int nInt = WEIGHT_NORMAL; + + // Special case fixes + + // tdf#67744: Courier Std Medium is always bold. We get a kCTFontWeightTrait of 0.23 which + // surely must be wrong. + if (rDFA.GetFamilyName() == "Courier Std" && + (rDFA.GetStyleName() == "Medium" || rDFA.GetStyleName() == "Medium Oblique") && + fWeight > 0.2) + { + fWeight = 0; + } + + // tdf#68889: Ditto for Gill Sans MT Pro. Here I can kinda understand it, maybe the + // kCTFontWeightTrait is intended to give a subjective "optical" impression of how the font + // looks, and Gill Sans MT Pro Medium is kinda heavy. But with the way LibreOffice uses fonts, + // we still should think of it as being "medium" weight. + if (rDFA.GetFamilyName() == "Gill Sans MT Pro" && + (rDFA.GetStyleName() == "Medium" || rDFA.GetStyleName() == "Medium Italic") && + fWeight > 0.2) + { + fWeight = 0; + } + + if( fWeight > 0 ) + { + nInt = rint(int(WEIGHT_NORMAL) + fWeight * ((WEIGHT_BLACK - WEIGHT_NORMAL)/0.68)); + if( nInt > WEIGHT_BLACK ) + { + nInt = WEIGHT_BLACK; + } + } + else if( fWeight < 0 ) + { + nInt = rint(int(WEIGHT_NORMAL) + fWeight * ((WEIGHT_NORMAL - WEIGHT_THIN)/0.8)); + if( nInt < WEIGHT_THIN ) + { + nInt = WEIGHT_THIN; + } + } + rDFA.SetWeight( static_cast(nInt) ); + + // get the font slant + double fSlant = 0; + CFNumberRef pSlantNum = static_cast(CFDictionaryGetValue( pAttrDict, kCTFontSlantTrait )); + CFNumberGetValue( pSlantNum, kCFNumberDoubleType, &fSlant ); + if( fSlant >= 0.035 ) + { + rDFA.SetItalic( ITALIC_NORMAL ); + } + // get width trait + double fWidth = 0; + CFNumberRef pWidthNum = static_cast(CFDictionaryGetValue( pAttrDict, kCTFontWidthTrait )); + CFNumberGetValue( pWidthNum, kCFNumberDoubleType, &fWidth ); + nInt = WIDTH_NORMAL; + + if( fWidth > 0 ) + { + nInt = rint( int(WIDTH_NORMAL) + fWidth * ((WIDTH_ULTRA_EXPANDED - WIDTH_NORMAL)/0.4)); + if( nInt > WIDTH_ULTRA_EXPANDED ) + { + nInt = WIDTH_ULTRA_EXPANDED; + } + } + else if( fWidth < 0 ) + { + nInt = rint( int(WIDTH_NORMAL) + fWidth * ((WIDTH_NORMAL - WIDTH_ULTRA_CONDENSED)/0.5)); + if( nInt < WIDTH_ULTRA_CONDENSED ) + { + nInt = WIDTH_ULTRA_CONDENSED; + } + } + rDFA.SetWidthType( static_cast(nInt) ); + + // release the attribute dict that we had copied + CFRelease( pAttrDict ); + + // TODO? also use the HEAD table if available to get more attributes +// CFDataRef CTFontCopyTable( CTFontRef, kCTFontTableHead, /*kCTFontTableOptionNoOptions*/kCTFontTableOptionExcludeSynthetic ); + + return rDFA; +} + +static void fontEnumCallBack( const void* pValue, void* pContext ) +{ + CTFontDescriptorRef pFD = static_cast(pValue); + + bool bFontEnabled; + FontAttributes rDFA = DevFontFromCTFontDescriptor( pFD, &bFontEnabled ); + + if( bFontEnabled) + { + const sal_IntPtr nFontId = reinterpret_cast(pValue); + rtl::Reference pFontData = new CoreTextFontFace( rDFA, nFontId ); + SystemFontList* pFontList = static_cast(pContext); + pFontList->AddFont( pFontData.get() ); + } +} + +SystemFontList::SystemFontList() + : mpCTFontCollection( nullptr ) + , mpCTFontArray( nullptr ) +{} + +SystemFontList::~SystemFontList() +{ + maFontContainer.clear(); + + if( mpCTFontArray ) + { + CFRelease( mpCTFontArray ); + } + if( mpCTFontCollection ) + { + CFRelease( mpCTFontCollection ); + } +} + +void SystemFontList::AddFont( CoreTextFontFace* pFontData ) +{ + sal_IntPtr nFontId = pFontData->GetFontId(); + maFontContainer[ nFontId ] = pFontData; +} + +void SystemFontList::AnnounceFonts( PhysicalFontCollection& rFontCollection ) const +{ + for(const auto& rEntry : maFontContainer ) + { + rFontCollection.Add( rEntry.second.get() ); + } +} + +CoreTextFontFace* SystemFontList::GetFontDataFromId( sal_IntPtr nFontId ) const +{ + auto it = maFontContainer.find( nFontId ); + if( it == maFontContainer.end() ) + { + return nullptr; + } + return (*it).second.get(); +} + +bool SystemFontList::Init() +{ + // enumerate available system fonts + static const int nMaxDictEntries = 8; + CFMutableDictionaryRef pCFDict = CFDictionaryCreateMutable( nullptr, + nMaxDictEntries, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks ); + + CFDictionaryAddValue( pCFDict, kCTFontCollectionRemoveDuplicatesOption, kCFBooleanTrue ); + mpCTFontCollection = CTFontCollectionCreateFromAvailableFonts( pCFDict ); + CFRelease( pCFDict ); + mpCTFontArray = CTFontCollectionCreateMatchingFontDescriptors( mpCTFontCollection ); + + const int nFontCount = CFArrayGetCount( mpCTFontArray ); + const CFRange aFullRange = CFRangeMake( 0, nFontCount ); + CFArrayApplyFunction( mpCTFontArray, aFullRange, fontEnumCallBack, this ); + + return true; +} + +SystemFontList* GetCoretextFontList() +{ + SystemFontList* pList = new SystemFontList(); + if( !pList->Init() ) + { + delete pList; + return nullptr; + } + + return pList; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx new file mode 100644 index 000000000..8dd09d176 --- /dev/null +++ b/vcl/quartz/salbmp.cxx @@ -0,0 +1,963 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef MACOSX +#include +#else +#include "saldatabasic.hxx" +#endif + +static const unsigned long k32BitRedColorMask = 0x00ff0000; +static const unsigned long k32BitGreenColorMask = 0x0000ff00; +static const unsigned long k32BitBlueColorMask = 0x000000ff; + +static bool isValidBitCount( sal_uInt16 nBitCount ) +{ + return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || + (nBitCount == 24) || (nBitCount == 32); +} + +QuartzSalBitmap::QuartzSalBitmap() + : mxCachedImage( nullptr ) + , mnBits(0) + , mnWidth(0) + , mnHeight(0) + , mnBytesPerRow(0) +{ +} + +QuartzSalBitmap::~QuartzSalBitmap() +{ + doDestroy(); +} + +bool QuartzSalBitmap::Create(CGLayerHolder const & rLayerHolder, int nBitmapBits, int nX, int nY, int nWidth, int nHeight, bool bFlipped) +{ + SAL_WARN_IF(!rLayerHolder.isSet(), "vcl", "QuartzSalBitmap::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(rLayerHolder.get()); + + if( nWidth >= static_cast(aLayerSize.width) - nX ) + nWidth = static_cast(aLayerSize.width) - nX; + + if( nHeight >= static_cast(aLayerSize.height) - nY ) + nHeight = static_cast(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 = { static_cast(-nX), static_cast(-nY) }; + if (maGraphicContext.isSet()) // remove warning + { + if( bFlipped ) + { + CGContextTranslateCTM( maGraphicContext.get(), 0, +mnHeight ); + + CGContextScaleCTM( maGraphicContext.get(), +1, -1 ); + } + + CGContextDrawLayerAtPoint(maGraphicContext.get(), aSrcPoint, rLayerHolder.get()); + } + return true; +} + +bool QuartzSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette ) +{ + if( !isValidBitCount( nBits ) ) + return false; + + maPalette = rBitmapPalette; + mnBits = nBits; + mnWidth = rSize.Width(); + mnHeight = rSize.Height(); + return AllocateUserData(); +} + +bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp ) +{ + return Create( rSalBmp, rSalBmp.GetBitCount() ); +} + +bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) +{ + return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() ); +} + +bool QuartzSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) +{ + const QuartzSalBitmap& rSourceBitmap = static_cast(rSalBmp); + + if (isValidBitCount(nNewBitCount) && rSourceBitmap.m_pUserBuffer.get()) + { + mnBits = nNewBitCount; + mnWidth = rSourceBitmap.mnWidth; + mnHeight = rSourceBitmap.mnHeight; + maPalette = rSourceBitmap.maPalette; + + if( AllocateUserData() ) + { + ConvertBitmapData( mnWidth, mnHeight, mnBits, mnBytesPerRow, maPalette, + m_pUserBuffer.get(), rSourceBitmap.mnBits, + rSourceBitmap.mnBytesPerRow, rSourceBitmap.maPalette, + rSourceBitmap.m_pUserBuffer.get() ); + return true; + } + } + return false; +} + +bool QuartzSalBitmap::Create( const css::uno::Reference< css::rendering::XBitmapCanvas >& /*xBitmapCanvas*/, + Size& /*rSize*/, bool /*bMask*/ ) +{ + return false; +} + +void QuartzSalBitmap::Destroy() +{ + doDestroy(); +} + +void QuartzSalBitmap::doDestroy() +{ + DestroyContext(); + m_pUserBuffer.reset(); +} + +void QuartzSalBitmap::DestroyContext() +{ + if( mxCachedImage ) + { + CGImageRelease( mxCachedImage ); + mxCachedImage = nullptr; + } + + if (maGraphicContext.isSet()) + { + CGContextRelease(maGraphicContext.get()); + maGraphicContext.set(nullptr); + m_pContextBuffer.reset(); + } +} + +bool QuartzSalBitmap::CreateContext() +{ + DestroyContext(); + + // prepare graphics context + // convert image from user input if available + const bool bSkipConversion = !m_pUserBuffer; + 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 = 8; + sal_uInt32 nContextBytesPerRow = mnBytesPerRow; + if( mnBits == 32 ) + { + // no conversion needed for truecolor + m_pContextBuffer = m_pUserBuffer; + } + else if( mnBits == 8 && maPalette.IsGreyPalette8Bit() ) + { + // no conversion needed for grayscale + m_pContextBuffer = m_pUserBuffer; + 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 + { + m_pContextBuffer = o3tl::make_shared_array(mnHeight * nContextBytesPerRow); + + if( !bSkipConversion ) + { + ConvertBitmapData( mnWidth, mnHeight, + 32, nContextBytesPerRow, maPalette, m_pContextBuffer.get(), + mnBits, mnBytesPerRow, maPalette, m_pUserBuffer.get() ); + } + } + catch( const std::bad_alloc& ) + { + maGraphicContext.set(nullptr); + } + } + + if (m_pContextBuffer.get()) + { + maGraphicContext.set(CGBitmapContextCreate(m_pContextBuffer.get(), mnWidth, mnHeight, + bitsPerComponent, nContextBytesPerRow, + aCGColorSpace, aCGBmpInfo)); + } + + if (!maGraphicContext.isSet()) + m_pContextBuffer.reset(); + + return maGraphicContext.isSet(); +} + +bool QuartzSalBitmap::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 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break; + case 32: mnBytesPerRow = mnWidth << 2; break; + default: + assert(false && "vcl::QuartzSalBitmap::AllocateUserData(), illegal bitcount!"); + } + } + + bool alloc = false; + if (mnBytesPerRow != 0 && + mnBytesPerRow <= std::numeric_limits::max() / mnHeight) + { + try + { + m_pUserBuffer = o3tl::make_shared_array(mnBytesPerRow * mnHeight); + alloc = true; + } + catch (std::bad_alloc &) {} + } + if (!alloc) + { + SAL_WARN( "vcl.quartz", "bad_alloc: " << mnWidth << "x" << mnHeight << " (" << mnBytesPerRow * mnHeight << " bytes)"); + m_pUserBuffer.reset(); + mnBytesPerRow = 0; + } + + return m_pUserBuffer.get() != nullptr; +} + +namespace { + +class ImplPixelFormat +{ +public: + static std::unique_ptr GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette ); + + virtual void StartLine( sal_uInt8* pLine ) = 0; + virtual void SkipPixel( sal_uInt32 nPixel ) = 0; + virtual Color ReadPixel() = 0; + virtual void WritePixel( Color nColor ) = 0; + virtual ~ImplPixelFormat() { } +}; + +class ImplPixelFormat32 : public ImplPixelFormat +// currently ARGB-format for 32bit depth +{ + sal_uInt8* pData; +public: + virtual void StartLine( sal_uInt8* pLine ) override { pData = pLine; } + virtual void SkipPixel( sal_uInt32 nPixel ) override + { + pData += nPixel << 2; + } + virtual Color ReadPixel() override + { + const Color c( pData[1], pData[2], pData[3] ); + pData += 4; + return c; + } + virtual void WritePixel( Color nColor ) override + { + *pData++ = 0; + *pData++ = nColor.GetRed(); + *pData++ = nColor.GetGreen(); + *pData++ = nColor.GetBlue(); + } +}; + +class ImplPixelFormat24 : public ImplPixelFormat +// currently BGR-format for 24bit depth +{ + sal_uInt8* pData; +public: + virtual void StartLine( sal_uInt8* pLine ) override { pData = pLine; } + virtual void SkipPixel( sal_uInt32 nPixel ) override + { + pData += (nPixel << 1) + nPixel; + } + virtual Color ReadPixel() override + { + const Color c( pData[2], pData[1], pData[0] ); + pData += 3; + return c; + } + virtual void WritePixel( Color nColor ) override + { + *pData++ = nColor.GetBlue(); + *pData++ = nColor.GetGreen(); + *pData++ = nColor.GetRed(); + } +}; + +class ImplPixelFormat8 : public ImplPixelFormat +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + const sal_uInt16 mnPaletteCount; + +public: + explicit ImplPixelFormat8( const BitmapPalette& rPalette ) + : pData(nullptr) + , mrPalette(rPalette) + , mnPaletteCount(rPalette.GetEntryCount()) + { + } + virtual void StartLine( sal_uInt8* pLine ) override { pData = pLine; } + virtual void SkipPixel( sal_uInt32 nPixel ) override + { + pData += nPixel; + } + virtual Color ReadPixel() override + { + const sal_uInt8 nIndex(*pData++); + + // Caution(!) rPalette.GetEntryCount() may be != (depth^^2)-1 (!) + if(nIndex < mnPaletteCount) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + virtual void WritePixel( Color nColor ) override + { + *pData++ = static_cast< sal_uInt8 >( mrPalette.GetBestIndex( nColor ) ); + } +}; + +class ImplPixelFormat4 : public ImplPixelFormat +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + const sal_uInt16 mnPaletteCount; + sal_uInt32 mnX; + sal_uInt32 mnShift; + +public: + explicit ImplPixelFormat4( const BitmapPalette& rPalette ) + : pData(nullptr) + , mrPalette(rPalette) + , mnPaletteCount(rPalette.GetEntryCount()) + , mnX(0) + , mnShift(0) + { + } + virtual void SkipPixel( sal_uInt32 nPixel ) override + { + mnX += nPixel; + if( nPixel & 1 ) + { + mnShift ^= 4; + } + } + virtual void StartLine( sal_uInt8* pLine ) override + { + pData = pLine; + mnX = 0; + mnShift = 4; + } + virtual Color ReadPixel() override + { + // Caution(!) rPalette.GetEntryCount() may be != (depth^^2)-1 (!) + const sal_uInt8 nIndex(( pData[mnX >> 1] >> mnShift) & 0x0f); + mnX++; + mnShift ^= 4; + + if(nIndex < mnPaletteCount) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + virtual void WritePixel( Color nColor ) override + { + pData[mnX>>1] &= (0xf0 >> mnShift); + pData[mnX>>1] |= (static_cast< sal_uInt8 >( mrPalette.GetBestIndex( nColor ) ) & 0x0f); + mnX++; + mnShift ^= 4; + } +}; + +class ImplPixelFormat1 : public ImplPixelFormat +{ +private: + sal_uInt8* pData; + const BitmapPalette& mrPalette; + const sal_uInt16 mnPaletteCount; + sal_uInt32 mnX; + +public: + explicit ImplPixelFormat1( const BitmapPalette& rPalette ) + : pData(nullptr) + , mrPalette(rPalette) + , mnPaletteCount(rPalette.GetEntryCount()) + , mnX(0) + { + } + virtual void SkipPixel( sal_uInt32 nPixel ) override + { + mnX += nPixel; + } + virtual void StartLine( sal_uInt8* pLine ) override + { + pData = pLine; + mnX = 0; + } + virtual Color ReadPixel() override + { + // Caution(!) rPalette.GetEntryCount() may be != (depth^^2)-1 (!) + const sal_uInt8 nIndex( (pData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1); + mnX++; + + if(nIndex < mnPaletteCount) + return mrPalette[nIndex]; + else + return COL_BLACK; + } + virtual void WritePixel( Color nColor ) override + { + if( mrPalette.GetBestIndex( nColor ) & 1 ) + { + pData[ mnX >> 3 ] |= 1 << ( 7 - ( mnX & 7 ) ); + } + else + { + pData[ mnX >> 3 ] &= ~( 1 << ( 7 - ( mnX & 7 ) ) ); + } + mnX++; + } +}; + +std::unique_ptr ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette ) +{ + switch( nBits ) + { + case 1: return std::make_unique( rPalette ); + case 4: return std::make_unique( rPalette ); + case 8: return std::make_unique( rPalette ); + case 24: return std::make_unique(); + case 32: return std::make_unique(); + default: + assert(false); + return nullptr; + } + + return nullptr; +} + +} // namespace + +void QuartzSalBitmap::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 = ScanlineFormat::N24BitTcBgr; + aSrcBuf.mpBits = pSrcData; + aSrcBuf.mnBitCount = nSrcBits; + aSrcBuf.mnScanlineSize = nSrcBytesPerRow; + BitmapBuffer aDstBuf; + aDstBuf.mnFormat = ScanlineFormat::N32BitTcArgb; + aDstBuf.mpBits = pDestData; + aDstBuf.mnBitCount = nDestBits; + aDstBuf.mnScanlineSize = nDestBytesPerRow; + + aSrcBuf.mnWidth = aDstBuf.mnWidth = nWidth; + aSrcBuf.mnHeight = aDstBuf.mnHeight = nHeight; + + SalTwoRect aTwoRects(0, 0, mnWidth, mnHeight, 0, 0, mnWidth, mnHeight); + bConverted = ::ImplFastBitmapConversion( aDstBuf, aSrcBuf, aTwoRects ); + } + + if( !bConverted ) + { + // TODO: this implementation is for clarity, not for speed + + std::unique_ptr pD = ImplPixelFormat::GetFormat( nDestBits, rDestPalette ); + std::unique_ptr 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; + } + } + } +} + +Size QuartzSalBitmap::GetSize() const +{ + return Size( mnWidth, mnHeight ); +} + +sal_uInt16 QuartzSalBitmap::GetBitCount() const +{ + return mnBits; +} + +namespace { + +struct pal_entry +{ + sal_uInt8 mnRed; + sal_uInt8 mnGreen; + sal_uInt8 mnBlue; +}; + +} + +static pal_entry 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 } +}; + +static 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 sal_uInt8 DITHER_PAL_DELTA = 51; + int nB, nG, nR; + sal_uInt8 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* QuartzSalBitmap::AcquireBuffer( BitmapAccessMode /*nMode*/ ) +{ + // TODO: AllocateUserData(); + if (!m_pUserBuffer.get()) + return nullptr; + + BitmapBuffer* pBuffer = new BitmapBuffer; + pBuffer->mnWidth = mnWidth; + pBuffer->mnHeight = mnHeight; + pBuffer->maPalette = maPalette; + pBuffer->mnScanlineSize = mnBytesPerRow; + pBuffer->mpBits = m_pUserBuffer.get(); + pBuffer->mnBitCount = mnBits; + switch( mnBits ) + { + case 1: + pBuffer->mnFormat = ScanlineFormat::N1BitMsbPal; + break; + case 4: + pBuffer->mnFormat = ScanlineFormat::N4BitMsnPal; + break; + case 8: + pBuffer->mnFormat = ScanlineFormat::N8BitPal; + break; + case 24: + pBuffer->mnFormat = ScanlineFormat::N24BitTcBgr; + break; + case 32: + { + pBuffer->mnFormat = ScanlineFormat::N32BitTcArgb; + ColorMaskElement aRedMask(k32BitRedColorMask); + aRedMask.CalcMaskShift(); + ColorMaskElement aGreenMask(k32BitGreenColorMask); + aGreenMask.CalcMaskShift(); + ColorMaskElement aBlueMask(k32BitBlueColorMask); + aBlueMask.CalcMaskShift(); + pBuffer->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask); + break; + } + default: assert(false); + } + + // some BitmapBuffer users depend on a complete palette + if( (mnBits <= 8) && !maPalette ) + pBuffer->maPalette = GetDefaultPalette( mnBits, true ); + + return pBuffer; +} + +void QuartzSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, BitmapAccessMode nMode ) +{ + // invalidate graphic context if we have different data + if( nMode == BitmapAccessMode::Write ) + { + maPalette = pBuffer->maPalette; + if (maGraphicContext.isSet()) + { + DestroyContext(); + } + InvalidateChecksum(); + } + + delete pBuffer; +} + +CGImageRef QuartzSalBitmap::CreateCroppedImage( int nX, int nY, int nNewWidth, int nNewHeight ) const +{ + if( !mxCachedImage ) + { + if (!maGraphicContext.isSet()) + { + if( !const_cast(this)->CreateContext() ) + { + return nullptr; + } + } + mxCachedImage = CGBitmapContextCreateImage(maGraphicContext.get()); + } + + CGImageRef xCroppedImage = nullptr; + // 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 = { { static_cast(nX), static_cast(nY) }, { static_cast(nNewWidth), static_cast(nNewHeight) } }; + xCroppedImage = CGImageCreateWithImageInRect( mxCachedImage, aCropRect ); + } + + return xCroppedImage; +} + +static void CFRTLFree(void* /*info*/, const void* data, size_t /*size*/) +{ + std::free( const_cast(data) ); +} + +CGImageRef QuartzSalBitmap::CreateWithMask( const QuartzSalBitmap& rMask, + int nX, int nY, int nWidth, int nHeight ) const +{ + CGImageRef xImage( CreateCroppedImage( nX, nY, nWidth, nHeight ) ); + if( !xImage ) + return nullptr; + + 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) || rMask.GetBitCount() != 8)//(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 = std::malloc( nMaskBytesPerRow * nHeight ); + CGContextRef xMaskContext = CGBitmapContextCreate( pMaskMem, + nWidth, nHeight, 8, nMaskBytesPerRow, GetSalData()->mxGraySpace, kCGImageAlphaNone ); + CGContextDrawImage( xMaskContext, xImageRect, xMask ); + CFRelease( xMask ); + CGDataProviderRef xDataProvider( CGDataProviderCreateWithData( nullptr, + pMaskMem, nHeight * nMaskBytesPerRow, &CFRTLFree ) ); + + static const CGFloat* pDecode = nullptr; + 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 QuartzSalBitmap::CreateColorMask( int nX, int nY, int nWidth, + int nHeight, Color nMaskColor ) const +{ + CGImageRef xMask = nullptr; + if (m_pUserBuffer.get() && (nX + nWidth <= mnWidth) && (nY + nHeight <= mnHeight)) + { + const sal_uInt32 nDestBytesPerRow = nWidth << 2; + std::unique_ptr pMaskBuffer(new (std::nothrow) sal_uInt32[ nHeight * nDestBytesPerRow / 4] ); + sal_uInt32* pDest = pMaskBuffer.get(); + + std::unique_ptr pSourcePixels = ImplPixelFormat::GetFormat( mnBits, maPalette ); + + if( pMaskBuffer && pSourcePixels ) + { + sal_uInt32 nColor; + reinterpret_cast(&nColor)[0] = 0xff; + reinterpret_cast(&nColor)[1] = nMaskColor.GetRed(); + reinterpret_cast(&nColor)[2] = nMaskColor.GetGreen(); + reinterpret_cast(&nColor)[3] = nMaskColor.GetBlue(); + + sal_uInt8* pSource = m_pUserBuffer.get(); + // First to nY on y-axis, as that is our starting point (sub-image) + if( nY ) + pSource += nY * mnBytesPerRow; + + int y = nHeight; + while( y-- ) + { + pSourcePixels->StartLine( pSource ); + pSourcePixels->SkipPixel(nX); // Skip on x axis to nX + sal_uInt32 x = nWidth; + while( x-- ) + { + *pDest++ = ( pSourcePixels->ReadPixel() == 0 ) ? nColor : 0; + } + pSource += mnBytesPerRow; + } + + CGDataProviderRef xDataProvider( CGDataProviderCreateWithData(nullptr, pMaskBuffer.release(), nHeight * nDestBytesPerRow, &CFRTLFree) ); + xMask = CGImageCreate(nWidth, nHeight, 8, 32, nDestBytesPerRow, GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedFirst, xDataProvider, nullptr, true, kCGRenderingIntentDefault); + CFRelease(xDataProvider); + } + } + return xMask; +} + +/** QuartzSalBitmap::GetSystemData Get platform native image data from existing image + * + * @param rData struct BitmapSystemData, defined in vcl/inc/bitmap.hxx + * @return true if successful +**/ +bool QuartzSalBitmap::GetSystemData( BitmapSystemData& rData ) +{ + bool bRet = false; + + if (!maGraphicContext.isSet()) + CreateContext(); + + if (maGraphicContext.isSet()) + { + bRet = true; + + if ((CGBitmapContextGetBitsPerPixel(maGraphicContext.get()) == 32) && + (CGBitmapContextGetBitmapInfo(maGraphicContext.get()) & kCGBitmapByteOrderMask) != kCGBitmapByteOrder32Host) + { + /** + * We need to hack things because VCL does not use kCGBitmapByteOrder32Host, while Cairo requires it. + * + * Not sure what the above comment means. We don't use Cairo on macOS or iOS. + * + * This whole if statement was originally (before 2011) inside #ifdef CAIRO. Did we use Cairo on Mac back then? + * Anyway, nowadays (since many years, I think) we don't, so should this if statement be dropped? Fun. + */ + + CGImageRef xImage = CGBitmapContextCreateImage(maGraphicContext.get()); + + // re-create the context with single change: include kCGBitmapByteOrder32Host flag. + CGContextHolder maGraphicContextNew(CGBitmapContextCreate(CGBitmapContextGetData(maGraphicContext.get()), + CGBitmapContextGetWidth(maGraphicContext.get()), + CGBitmapContextGetHeight(maGraphicContext.get()), + CGBitmapContextGetBitsPerComponent(maGraphicContext.get()), + CGBitmapContextGetBytesPerRow(maGraphicContext.get()), + CGBitmapContextGetColorSpace(maGraphicContext.get()), + CGBitmapContextGetBitmapInfo(maGraphicContext.get()) | kCGBitmapByteOrder32Host)); + CFRelease(maGraphicContext.get()); + + // Needs to be flipped + maGraphicContextNew.saveState(); + CGContextTranslateCTM (maGraphicContextNew.get(), 0, CGBitmapContextGetHeight(maGraphicContextNew.get())); + CGContextScaleCTM (maGraphicContextNew.get(), 1.0, -1.0); + + CGContextDrawImage(maGraphicContextNew.get(), CGRectMake( 0, 0, CGImageGetWidth(xImage), CGImageGetHeight(xImage)), xImage); + + // Flip back + CGContextRestoreGState( maGraphicContextNew.get() ); + CGImageRelease( xImage ); + maGraphicContext = maGraphicContextNew; + } + + rData.mnWidth = mnWidth; + rData.mnHeight = mnHeight; + } + + return bRet; +} + +bool QuartzSalBitmap::ScalingSupported() const +{ + return false; +} + +bool QuartzSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, BmpScaleFlag /*nScaleFlag*/ ) +{ + return false; +} + +bool QuartzSalBitmap::Replace( const Color& /*rSearchColor*/, const Color& /*rReplaceColor*/, sal_uInt8 /*nTol*/ ) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx new file mode 100644 index 000000000..83aebe2ab --- /dev/null +++ b/vcl/quartz/salgdi.cxx @@ -0,0 +1,888 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef MACOSX +#include +#endif +#include +#ifdef IOS +#include "saldatabasic.hxx" +#endif +#include +#include + +using namespace vcl; + +namespace { + +class CoreTextGlyphFallbackSubstititution +: public ImplGlyphFallbackFontSubstitution +{ +public: + bool FindFontSubstitute(FontSelectPattern&, LogicalFontInstance* pLogicalFont, OUString&) const override; +}; + +} + +bool CoreTextGlyphFallbackSubstititution::FindFontSubstitute(FontSelectPattern& rPattern, LogicalFontInstance* pLogicalFont, + OUString& rMissingChars) const +{ + bool bFound = false; + CoreTextStyle* pStyle = static_cast(pLogicalFont); + CTFontRef pFont = static_cast(CFDictionaryGetValue(pStyle->GetStyleDict(), kCTFontAttributeName)); + CFStringRef pStr = CreateCFString(rMissingChars); + if (pStr) + { + CTFontRef pFallback = CTFontCreateForString(pFont, pStr, CFRangeMake(0, CFStringGetLength(pStr))); + if (pFallback) + { + bFound = true; + + CTFontDescriptorRef pDesc = CTFontCopyFontDescriptor(pFallback); + FontAttributes rAttr = DevFontFromCTFontDescriptor(pDesc, nullptr); + + rPattern.maSearchName = rAttr.GetFamilyName(); + + rPattern.SetWeight(rAttr.GetWeight()); + rPattern.SetItalic(rAttr.GetItalic()); + rPattern.SetPitch(rAttr.GetPitch()); + rPattern.SetWidthType(rAttr.GetWidthType()); + + CFRelease(pFallback); + CFRelease(pDesc); + } + CFRelease(pStr); + } + + return bFound; +} + +CoreTextFontFace::CoreTextFontFace( const FontAttributes& rDFA, sal_IntPtr nFontId ) + : PhysicalFontFace( rDFA ) + , mnFontId( nFontId ) + , mbFontCapabilitiesRead( false ) +{ +} + +CoreTextFontFace::~CoreTextFontFace() +{ +} + +sal_IntPtr CoreTextFontFace::GetFontId() const +{ + return mnFontId; +} + +FontCharMapRef CoreTextFontFace::GetFontCharMap() const +{ + // return the cached charmap + if( mxCharMap.is() ) + return mxCharMap; + + // set the default charmap + FontCharMapRef pCharMap( new FontCharMap() ); + mxCharMap = pCharMap; + + // get the CMAP byte size + // allocate a buffer for the CMAP raw data + const int nBufSize = GetFontTable( "cmap", nullptr ); + SAL_WARN_IF( (nBufSize <= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable1 failed!"); + if( nBufSize <= 0 ) + return mxCharMap; + + // get the CMAP raw data + std::vector aBuffer( nBufSize ); + const int nRawLength = GetFontTable( "cmap", aBuffer.data() ); + SAL_WARN_IF( (nRawLength <= 0), "vcl", "CoreTextFontFace::GetFontCharMap : GetFontTable2 failed!"); + if( nRawLength <= 0 ) + return mxCharMap; + + SAL_WARN_IF( (nBufSize!=nRawLength), "vcl", "CoreTextFontFace::GetFontCharMap : ByteCount mismatch!"); + + // parse the CMAP + CmapResult aCmapResult; + if( ParseCMAP( aBuffer.data(), nRawLength, aCmapResult ) ) + { + FontCharMapRef xDefFontCharMap( new FontCharMap(aCmapResult) ); + // create the matching charmap + mxCharMap = xDefFontCharMap; + } + + return mxCharMap; +} + +bool CoreTextFontFace::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +{ + // read this only once per font + if( mbFontCapabilitiesRead ) + { + rFontCapabilities = maFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; + } + mbFontCapabilitiesRead = true; + + int nBufSize = GetFontTable( "OS/2", nullptr ); + if( nBufSize > 0 ) + { + // allocate a buffer for the OS/2 raw data + std::vector aBuffer( nBufSize ); + // get the OS/2 raw data + const int nRawLength = GetFontTable( "OS/2", aBuffer.data() ); + if( nRawLength > 0 ) + { + const unsigned char* pOS2Table = aBuffer.data(); + vcl::getTTCoverage( maFontCapabilities.oUnicodeRange, + maFontCapabilities.oCodePageRange, + pOS2Table, nRawLength); + } + } + rFontCapabilities = maFontCapabilities; + return rFontCapabilities.oUnicodeRange || rFontCapabilities.oCodePageRange; +} + +AquaSalGraphics::AquaSalGraphics() + : mpXorEmulation( nullptr ) + , mnXorMode( 0 ) + , mnWidth( 0 ) + , mnHeight( 0 ) + , mnBitmapDepth( 0 ) + , mnRealDPIX( 0 ) + , mnRealDPIY( 0 ) + , mxClipPath( nullptr ) + , maLineColor( COL_WHITE ) + , maFillColor( COL_BLACK ) + , maTextColor( COL_BLACK ) + , mbNonAntialiasedText( false ) +#ifdef MACOSX + , mpFrame( nullptr ) +#endif + , mbPrinter( false ) + , mbVirDev( false ) +#ifdef MACOSX + , mbWindow( false ) +#else + , mbForeignContext( false ) +#endif +{ + SAL_INFO( "vcl.quartz", "AquaSalGraphics::AquaSalGraphics() this=" << this ); + + for (int i = 0; i < MAX_FALLBACK; ++i) + mpTextStyle[i] = nullptr; + + if (comphelper::LibreOfficeKit::isActive()) + initWidgetDrawBackends(true); +} + +AquaSalGraphics::~AquaSalGraphics() +{ + SAL_INFO( "vcl.quartz", "AquaSalGraphics::~AquaSalGraphics() this=" << this ); + + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + } + + ReleaseFonts(); + + if( mpXorEmulation ) + delete mpXorEmulation; + +#ifdef IOS + if (mbForeignContext) + return; +#endif + if (maLayer.isSet()) + { + CGLayerRelease(maLayer.get()); + } + else if (maContextHolder.isSet() +#ifdef MACOSX + && mbWindow +#endif + ) + { + // destroy backbuffer bitmap context that we created ourself + CGContextRelease(maContextHolder.get()); + maContextHolder.set(nullptr); + } +} + +SalGraphicsImpl* AquaSalGraphics::GetImpl() const +{ + return nullptr; +} + +void AquaSalGraphics::SetTextColor( Color nColor ) +{ + maTextColor = RGBAColor( nColor ); + // SAL_ DEBUG(std::hex << nColor << std::dec << "={" << maTextColor.GetRed() << ", " << maTextColor.GetGreen() << ", " << maTextColor.GetBlue() << ", " << maTextColor.GetAlpha() << "}"); +} + +void AquaSalGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int nFallbackLevel) +{ + if (nFallbackLevel < MAX_FALLBACK && mpTextStyle[nFallbackLevel]) + { + mpTextStyle[nFallbackLevel]->GetFontMetric(rxFontMetric); + } +} + +static bool AddTempDevFont(const OUString& rFontFileURL) +{ + OUString aUSytemPath; + OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) ); + OString aCFileName = OUStringToOString( aUSytemPath, RTL_TEXTENCODING_UTF8 ); + + CFStringRef rFontPath = CFStringCreateWithCString(nullptr, aCFileName.getStr(), kCFStringEncodingUTF8); + CFURLRef rFontURL = CFURLCreateWithFileSystemPath(nullptr, rFontPath, kCFURLPOSIXPathStyle, true); + + CFErrorRef error; + bool success = CTFontManagerRegisterFontsForURL(rFontURL, kCTFontManagerScopeProcess, &error); + if (!success) + { + CFRelease(error); + } + CFRelease(rFontPath); + CFRelease(rFontURL); + + return success; +} + +static void AddTempFontDir( const OUString &rFontDirUrl ) +{ + osl::Directory aFontDir( rFontDirUrl ); + osl::FileBase::RC rcOSL = aFontDir.open(); + if( rcOSL == osl::FileBase::E_None ) + { + osl::DirectoryItem aDirItem; + + while( aFontDir.getNextItem( aDirItem, 10 ) == osl::FileBase::E_None ) + { + osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL ); + rcOSL = aDirItem.getFileStatus( aFileStatus ); + if ( rcOSL == osl::FileBase::E_None ) + { + AddTempDevFont(aFileStatus.getFileURL()); + } + } + } +} + +static void AddLocalTempFontDirs() +{ + static bool bFirst = true; + if( !bFirst ) + return; + + bFirst = false; + + // add private font files + + OUString aBrandStr( "$BRAND_BASE_DIR" ); + rtl_bootstrap_expandMacros( &aBrandStr.pData ); + + // internal font resources, required for normal operation, like OpenSymbol + AddTempFontDir( aBrandStr + "/" LIBO_SHARE_RESOURCE_FOLDER "/common/fonts/" ); + + AddTempFontDir( aBrandStr + "/" LIBO_SHARE_FOLDER "/fonts/truetype/" ); +} + +void AquaSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) +{ + SAL_WARN_IF( !pFontCollection, "vcl", "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 ) + pSalData->mpFontList = GetCoretextFontList(); + + // Copy all PhysicalFontFace objects contained in the SystemFontList + pSalData->mpFontList->AnnounceFonts( *pFontCollection ); + + static CoreTextGlyphFallbackSubstititution aSubstFallback; + pFontCollection->SetFallbackHook(&aSubstFallback); +} + +void AquaSalGraphics::ClearDevFontCache() +{ + SalData* pSalData = GetSalData(); + delete pSalData->mpFontList; + pSalData->mpFontList = nullptr; +} + +bool AquaSalGraphics::AddTempDevFont( PhysicalFontCollection*, + const OUString& rFontFileURL, const OUString& /*rFontName*/ ) +{ + return ::AddTempDevFont(rFontFileURL); +} + +void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout) +{ +#ifdef IOS + if (!CheckContext()) + { + SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout() without context"); + return; + } +#endif + + const CoreTextStyle& rStyle = *static_cast(&rLayout.GetFont()); + const FontSelectPattern& rFontSelect = rStyle.GetFontSelectPattern(); + if (rFontSelect.mnHeight == 0) + { + SAL_WARN("vcl.quartz", "AquaSalGraphics::DrawTextLayout(): rFontSelect.mnHeight is zero!?"); + return; + } + + CTFontRef pFont = static_cast(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName)); + CGAffineTransform aRotMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation); + + Point aPos; + const GlyphItem* pGlyph; + std::vector aGlyphIds; + std::vector aGlyphPos; + std::vector aGlyphOrientation; + int nStart = 0; + while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) + { + CGPoint aGCPos = CGPointMake(aPos.X(), -aPos.Y()); + + // Whether the glyph should be upright in vertical mode or not + bool bUprightGlyph = false; + + if (rStyle.mfFontRotation) + { + if (pGlyph->IsVertical()) + { + bUprightGlyph = true; + // Adjust the position of upright (vertical) glyphs. + aGCPos.y -= CTFontGetAscent(pFont) - CTFontGetDescent(pFont); + } + else + { + // Transform the position of rotated glyphs. + aGCPos = CGPointApplyAffineTransform(aGCPos, aRotMatrix); + } + } + + aGlyphIds.push_back(pGlyph->glyphId()); + aGlyphPos.push_back(aGCPos); + aGlyphOrientation.push_back(bUprightGlyph); + } + + if (aGlyphIds.empty()) + return; + + assert(aGlyphIds.size() == aGlyphPos.size()); +#if 0 + std::cerr << "aGlyphIds:["; + for (unsigned i = 0; i < aGlyphIds.size(); i++) + { + if (i > 0) + std::cerr << ","; + std::cerr << aGlyphIds[i]; + } + std::cerr << "]\n"; + std::cerr << "aGlyphPos:["; + for (unsigned i = 0; i < aGlyphPos.size(); i++) + { + if (i > 0) + std::cerr << ","; + std::cerr << aGlyphPos[i]; + } + std::cerr << "]\n"; +#endif + + maContextHolder.saveState(); + + // The view is vertically flipped (no idea why), flip it back. + CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0); + CGContextSetShouldAntialias(maContextHolder.get(), !mbNonAntialiasedText); + CGContextSetFillColor(maContextHolder.get(), maTextColor.AsArray()); + + if (rStyle.mbFauxBold) + { + + float fSize = rFontSelect.mnHeight / 23.0f; + CGContextSetStrokeColor(maContextHolder.get(), maTextColor.AsArray()); + CGContextSetLineWidth(maContextHolder.get(), fSize); + CGContextSetTextDrawingMode(maContextHolder.get(), kCGTextFillStroke); + } + + auto aIt = aGlyphOrientation.cbegin(); + while (aIt != aGlyphOrientation.cend()) + { + bool bUprightGlyph = *aIt; + // Find the boundary of the run of glyphs with the same rotation, to be + // drawn together. + auto aNext = std::find(aIt, aGlyphOrientation.cend(), !bUprightGlyph); + size_t nStartIndex = std::distance(aGlyphOrientation.cbegin(), aIt); + size_t nLen = std::distance(aIt, aNext); + + maContextHolder.saveState(); + if (rStyle.mfFontRotation && !bUprightGlyph) + { + CGContextRotateCTM(maContextHolder.get(), rStyle.mfFontRotation); + } + CTFontDrawGlyphs(pFont, &aGlyphIds[nStartIndex], &aGlyphPos[nStartIndex], nLen, maContextHolder.get()); + maContextHolder.restoreState(); + + aIt = aNext; + } + + maContextHolder.restoreState(); +} + +void AquaSalGraphics::SetFont(LogicalFontInstance* pReqFont, int nFallbackLevel) +{ + // release the text style + for (int i = nFallbackLevel; i < MAX_FALLBACK; ++i) + { + if (!mpTextStyle[i]) + break; + mpTextStyle[i].clear(); + } + + if (!pReqFont) + return; + + // update the text style + mpTextStyle[nFallbackLevel] = static_cast(pReqFont); +} + +std::unique_ptr AquaSalGraphics::GetTextLayout(int nFallbackLevel) +{ + assert(mpTextStyle[nFallbackLevel]); + if (!mpTextStyle[nFallbackLevel]) + return nullptr; + return std::make_unique(*mpTextStyle[nFallbackLevel]); +} + +FontCharMapRef AquaSalGraphics::GetFontCharMap() const +{ + if (!mpTextStyle[0]) + { + return FontCharMapRef( new FontCharMap() ); + } + + return static_cast(mpTextStyle[0]->GetFontFace())->GetFontCharMap(); +} + +bool AquaSalGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +{ + if (!mpTextStyle[0]) + return false; + + return static_cast(mpTextStyle[0]->GetFontFace())->GetFontCapabilities(rFontCapabilities); +} + +// fake a SFNT font directory entry for a font table +// see http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html#Directory +static void FakeDirEntry( const char aTag[5], ByteCount nOfs, ByteCount nLen, + const unsigned char* /*pData*/, unsigned char*& rpDest ) +{ + // write entry tag + rpDest[ 0] = aTag[0]; + rpDest[ 1] = aTag[1]; + rpDest[ 2] = aTag[2]; + rpDest[ 3] = aTag[3]; + // 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] = static_cast(nOfs >> 24); + rpDest[ 9] = static_cast(nOfs >> 16); + rpDest[10] = static_cast(nOfs >> 8); + rpDest[11] = static_cast(nOfs >> 0); + // write entry length + rpDest[12] = static_cast(nLen >> 24); + rpDest[13] = static_cast(nLen >> 16); + rpDest[14] = static_cast(nLen >> 8); + rpDest[15] = static_cast(nLen >> 0); + // advance to next entry + rpDest += 16; +} + +// fake a TTF or CFF font as directly accessing font file is not possible +// when only the fontid is known. This approach also handles *.font fonts. +bool AquaSalGraphics::GetRawFontData( const PhysicalFontFace* pFontData, + std::vector& rBuffer, bool* pJustCFF ) +{ + const CoreTextFontFace* pMacFont = static_cast(pFontData); + + // short circuit for CFF-only fonts + const int nCffSize = pMacFont->GetFontTable( "CFF ", nullptr); + if( pJustCFF != nullptr ) + { + *pJustCFF = (nCffSize > 0); + if( *pJustCFF) + { + rBuffer.resize( nCffSize); + const int nCffRead = pMacFont->GetFontTable( "CFF ", rBuffer.data()); + if( nCffRead != nCffSize) + { + return false; + } + return true; + } + } + + // get font table availability and size in bytes + const int nHeadSize = pMacFont->GetFontTable( "head", nullptr); + if( nHeadSize <= 0) + return false; + + const int nMaxpSize = pMacFont->GetFontTable( "maxp", nullptr); + if( nMaxpSize <= 0) + return false; + + const int nCmapSize = pMacFont->GetFontTable( "cmap", nullptr); + if( nCmapSize <= 0) + return false; + + const int nNameSize = pMacFont->GetFontTable( "name", nullptr); + if( nNameSize <= 0) + return false; + + const int nHheaSize = pMacFont->GetFontTable( "hhea", nullptr); + if( nHheaSize <= 0) + return false; + + const int nHmtxSize = pMacFont->GetFontTable( "hmtx", nullptr); + if( nHmtxSize <= 0) + return false; + + // get the ttf-glyf outline tables + int nLocaSize = 0; + int nGlyfSize = 0; + if( nCffSize <= 0) + { + nLocaSize = pMacFont->GetFontTable( "loca", nullptr); + if( nLocaSize <= 0) + return false; + + nGlyfSize = pMacFont->GetFontTable( "glyf", nullptr); + if( nGlyfSize <= 0) + return false; + } + + int nPrepSize = 0, nCvtSize = 0, nFpgmSize = 0; + if( nGlyfSize) // TODO: reduce PDF size by making hint subsetting optional + { + nPrepSize = pMacFont->GetFontTable( "prep", nullptr); + nCvtSize = pMacFont->GetFontTable( "cvt ", nullptr); + nFpgmSize = pMacFont->GetFontTable( "fpgm", nullptr); + } + + // prepare a byte buffer for a fake font + int nTableCount = 7; + nTableCount += (nPrepSize>0?1:0) + (nCvtSize>0?1:0) + (nFpgmSize>0?1:0) + (nGlyfSize>0?1:0); + const ByteCount nFdirSize = 12 + 16*nTableCount; + ByteCount nTotalSize = nFdirSize; + nTotalSize += nHeadSize + nMaxpSize + nNameSize + nCmapSize; + + if( nGlyfSize ) + { + nTotalSize += nLocaSize + nGlyfSize; + } + else + { + nTotalSize += nCffSize; + } + nTotalSize += nHheaSize + nHmtxSize; + nTotalSize += nPrepSize + nCvtSize + nFpgmSize; + rBuffer.resize( nTotalSize ); + + // 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 = nFdirSize; + unsigned char* pFakeEntry = &rBuffer[12]; + if( nCmapSize != pMacFont->GetFontTable( "cmap", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "cmap", nOfs, nCmapSize, rBuffer.data(), pFakeEntry ); + nOfs += nCmapSize; + if( nCvtSize ) + { + if( nCvtSize != pMacFont->GetFontTable( "cvt ", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "cvt ", nOfs, nCvtSize, rBuffer.data(), pFakeEntry ); + nOfs += nCvtSize; + } + if( nFpgmSize ) + { + if( nFpgmSize != pMacFont->GetFontTable( "fpgm", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "fpgm", nOfs, nFpgmSize, rBuffer.data(), pFakeEntry ); + nOfs += nFpgmSize; + } + if( nCffSize ) + { + if( nCffSize != pMacFont->GetFontTable( "CFF ", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "CFF ", nOfs, nCffSize, rBuffer.data(), pFakeEntry ); + nOfs += nGlyfSize; + } + else + { + if( nGlyfSize != pMacFont->GetFontTable( "glyf", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "glyf", nOfs, nGlyfSize, rBuffer.data(), pFakeEntry ); + nOfs += nGlyfSize; + + if( nLocaSize != pMacFont->GetFontTable( "loca", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "loca", nOfs, nLocaSize, rBuffer.data(), pFakeEntry ); + nOfs += nLocaSize; + } + if( nHeadSize != pMacFont->GetFontTable( "head", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "head", nOfs, nHeadSize, rBuffer.data(), pFakeEntry ); + nOfs += nHeadSize; + + if( nHheaSize != pMacFont->GetFontTable( "hhea", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "hhea", nOfs, nHheaSize, rBuffer.data(), pFakeEntry ); + nOfs += nHheaSize; + if( nHmtxSize != pMacFont->GetFontTable( "hmtx", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "hmtx", nOfs, nHmtxSize, rBuffer.data(), pFakeEntry ); + nOfs += nHmtxSize; + if( nMaxpSize != pMacFont->GetFontTable( "maxp", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "maxp", nOfs, nMaxpSize, rBuffer.data(), pFakeEntry ); + nOfs += nMaxpSize; + if( nNameSize != pMacFont->GetFontTable( "name", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "name", nOfs, nNameSize, rBuffer.data(), pFakeEntry ); + nOfs += nNameSize; + if( nPrepSize ) + { + if( nPrepSize != pMacFont->GetFontTable( "prep", &rBuffer[nOfs])) + return false; + + FakeDirEntry( "prep", nOfs, nPrepSize, rBuffer.data(), pFakeEntry ); + nOfs += nPrepSize; + } + + SAL_WARN_IF( (nOfs!=nTotalSize), "vcl", "AquaSalGraphics::GetRawFontData (nOfs!=nTotalSize)"); + + return true; +} + +void AquaSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFontData, bool bVertical, + std::vector< sal_Int32 >& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc ) +{ + rGlyphWidths.clear(); + rUnicodeEnc.clear(); + + std::vector aBuffer; + if( !GetRawFontData( pFontData, aBuffer, nullptr ) ) + 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 = nullptr; + SFErrCodes nRC = ::OpenTTFontBuffer( static_cast(aBuffer.data()), aBuffer.size(), 0, &pSftFont); + if( nRC != SFErrCodes::Ok ) + return; + + const int nGlyphCount = ::GetTTGlyphCount( pSftFont ); + if( nGlyphCount > 0 ) + { + // get glyph metrics + rGlyphWidths.resize(nGlyphCount); + std::vector aGlyphIds(nGlyphCount); + for( int i = 0; i < nGlyphCount; i++ ) + { + aGlyphIds[i] = static_cast(i); + } + + std::unique_ptr pGlyphMetrics = ::GetTTSimpleGlyphMetrics( pSftFont, aGlyphIds.data(), + nGlyphCount, bVertical ); + if( pGlyphMetrics ) + { + for( int i = 0; i < nGlyphCount; ++i ) + { + rGlyphWidths[i] = pGlyphMetrics[i]; + } + pGlyphMetrics.reset(); + } + + rtl::Reference rCTFontData(new CoreTextFontFace(*pFontData, pFontData->GetFontId())); + FontCharMapRef xFCMap = rCTFontData->GetFontCharMap(); + SAL_WARN_IF( !xFCMap.is() || !xFCMap->GetCharCount(), "vcl", "no charmap" ); + + // get unicode<->glyph encoding + // TODO? avoid sft mapping by using the xFCMap itself + int nCharCount = xFCMap->GetCharCount(); + sal_uInt32 nChar = xFCMap->GetFirstChar(); + for( ; --nCharCount >= 0; nChar = xFCMap->GetNextChar( nChar ) ) + { + if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars + break; + + sal_Ucs nUcsChar = static_cast(nChar); + sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar ); + if( nGlyph > 0 ) + { + rUnicodeEnc[ nUcsChar ] = nGlyph; + } + } + + xFCMap = nullptr; + } + + ::CloseTTFont( pSftFont ); +} + +const void* AquaSalGraphics::GetEmbedFontData(const PhysicalFontFace*, long* /*pDataLen*/) +{ + return nullptr; +} + +void AquaSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ ) +{ + // TODO: implementing this only makes sense when the implementation of + // AquaSalGraphics::GetEmbedFontData() returns non-NULL + SAL_WARN_IF( (pData==nullptr), "vcl", "AquaSalGraphics::FreeEmbedFontData() is not implemented"); +} + +bool AquaSalGraphics::IsFlipped() const +{ +#ifdef MACOSX + return mbWindow; +#else + return false; +#endif +} + +void AquaSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight) +{ +#ifdef MACOSX + if( ! mbWindow ) // view only on Window graphics + return; + + if( mpFrame ) + { + // update a little more around the designated rectangle + // this helps with antialiased rendering + // Rounding down x and width can accumulate a rounding error of up to 2 + // The decrementing of x, the rounding error and the antialiasing border + // require that the width and the height need to be increased by four + const tools::Rectangle aVclRect(Point(static_cast(lX-1), + static_cast(lY-1) ), + Size( static_cast(lWidth+4), + static_cast(lHeight+4) ) ); + mpFrame->maInvalidRect.Union( aVclRect ); + } +#else + (void) lX; + (void) lY; + (void) lWidth; + (void) lHeight; + return; +#endif +} + +#ifdef IOS + +bool AquaSalGraphics::CheckContext() +{ + if (mbForeignContext) + { + SAL_INFO("vcl.ios", "CheckContext() this=" << this << ", mbForeignContext, return true"); + return true; + } + + SAL_INFO( "vcl.ios", "CheckContext() this=" << this << ", not foreign, return false"); + return false; +} + +CGContextRef AquaSalGraphics::GetContext() +{ + if (!maContextHolder.isSet()) + CheckContext(); + + return maContextHolder.get(); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx new file mode 100644 index 000000000..8b51e91c6 --- /dev/null +++ b/vcl/quartz/salgdicommon.cxx @@ -0,0 +1,2047 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#ifdef MACOSX +#include +#endif +#include +#ifdef IOS +#include "saldatabasic.hxx" +#endif +#include + +using namespace vcl; + +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; + } + + 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, nullptr, aPoint.getX(), aPoint.getY() ); + continue; + } + + bool bPendingCurve = false; + if( bHasCurves ) + { + bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); + bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); + } + + if( !bPendingCurve ) // line segment + { + CGPathAddLineToPoint( xPath, nullptr, 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, nullptr, 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 + if( rPolyPoly.count() == 0 ) + { + return; + } + for(auto const& rPolygon : rPolyPoly) + { + AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw ); + } +} + +bool AquaSalGraphics::CreateFontSubset( const OUString& rToFile, + const PhysicalFontFace* pFontData, + const sal_GlyphId* pGlyphIds, const 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 + OUString aSysPath; + if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) ) + { + return false; + } + + // get the raw-bytes from the font to be subset + std::vector aBuffer; + bool bCffOnly = false; + if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) ) + { + return false; + } + const OString aToFile( OUStringToOString( aSysPath, + osl_getThreadTextEncoding())); + + // handle CFF-subsetting + if( bCffOnly ) + { + // provide the raw-CFF data to the subsetter + ByteCount nCffLen = aBuffer.size(); + rInfo.LoadFont( FontType::CFF_FONT, aBuffer.data(), nCffLen ); + + // NOTE: assuming that all glyphids requested on Aqua are fully translated + + // make the subsetter provide the requested subset + FILE* pOutFile = fopen( aToFile.getStr(), "wb" ); + bool bRC = rInfo.CreateFontSubset( FontType::TYPE1_PFB, pOutFile, nullptr, + 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 = nullptr; + SFErrCodes nRC = ::OpenTTFontBuffer( static_cast(aBuffer.data()), aBuffer.size(), 0, &pSftFont); + if( nRC != SFErrCodes::Ok ) + { + return false; + } + // get details about the subsetted font + TTGlobalFontInfo aTTInfo; + ::GetTTGlobalFontInfo( pSftFont, &aTTInfo ); + rInfo.m_nFontType = FontType::SFNT_TTF; + rInfo.m_aPSName = OUString( aTTInfo.psname, std::strlen(aTTInfo.psname), + RTL_TEXTENCODING_UTF8 ); + rInfo.m_aFontBBox = tools::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; + sal_uInt16 aShortIDs[ 257 ]; + sal_uInt8 aTempEncs[ 257 ]; + int nNotDef = -1; + + assert( (nGlyphCount <= 256 && "too many glyphs for subsetting" )); + + for( int i = 0; i < nGlyphCount; ++i ) + { + aTempEncs[i] = pEncoding[i]; + + sal_GlyphId aGlyphId(pGlyphIds[i]); + aShortIDs[i] = static_cast( aGlyphId ); + if( !aGlyphId && 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; + } + + // TODO: where to get bVertical? + const bool bVertical = false; + + // fill the pGlyphWidths array + // while making sure that the NotDef glyph is at index==0 + std::unique_ptr pGlyphMetrics = ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, + nGlyphCount, bVertical ); + if( !pGlyphMetrics ) + { + return false; + } + + sal_uInt16 nNotDefAdv = pGlyphMetrics[0]; + pGlyphMetrics[0] = pGlyphMetrics[nNotDef]; + pGlyphMetrics[nNotDef] = nNotDefAdv; + for( int i = 0; i < nOrigCount; ++i ) + { + pGlyphWidths[i] = pGlyphMetrics[i]; + } + pGlyphMetrics.reset(); + + // write subset into destination file + nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.getStr(), aShortIDs, + aTempEncs, nGlyphCount ); + ::CloseTTFont(pSftFont); + return (nRC == SFErrCodes::Ok); +} + +static void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY ) +{ + o_fX = static_cast(i_pIn->mnX ) + 0.5; + o_fY = static_cast(i_pIn->mnY ) + 0.5; +} + +void AquaSalGraphics::copyBits( const SalTwoRect& rPosAry, 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( rPosAry.mnSrcWidth <= 0 || + rPosAry.mnSrcHeight <= 0 || + rPosAry.mnDestWidth <= 0 || + rPosAry.mnDestHeight <= 0 ) + { + return; + } + +#ifdef IOS + // If called from idle layout, maContextHolder.get() is NULL, no idea what to do + if (!maContextHolder.isSet()) + return; +#endif + + // accelerate trivial operations + /*const*/ AquaSalGraphics* pSrc = static_cast(pSrcGraphics); + const bool bSameGraphics = (this == pSrc) +#ifdef MACOSX + || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame)) +#endif + ; + + if( bSameGraphics && + (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight)) + { + // short circuit if there is nothing to do + if( (rPosAry.mnSrcX == rPosAry.mnDestX) && + (rPosAry.mnSrcY == rPosAry.mnDestY)) + { + return; + } + // use copyArea() if source and destination context are identical + copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, false/*bWindowInvalidate*/ ); + return; + } + + ApplyXorContext(); + pSrc->ApplyXorContext(); + + SAL_WARN_IF (!pSrc->maLayer.isSet(), "vcl.quartz", + "AquaSalGraphics::copyBits() from non-layered graphics this=" << this); + + const CGPoint aDstPoint = CGPointMake(+rPosAry.mnDestX - rPosAry.mnSrcX, rPosAry.mnDestY - rPosAry.mnSrcY); + if ((rPosAry.mnSrcWidth == rPosAry.mnDestWidth && + rPosAry.mnSrcHeight == rPosAry.mnDestHeight) && + (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) + && pSrc->maLayer.isSet()) // workaround for a Quartz crash + { + // 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 + CGContextHolder aCopyContext = maContextHolder; + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + if( pSrcGraphics == this ) + { + aCopyContext.set(mpXorEmulation->GetTargetContext()); + } + } + aCopyContext.saveState(); + + const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + CGContextClipToRect(aCopyContext.get(), aDstRect); + + // draw at new destination + // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down + if( pSrc->IsFlipped() ) + { + CGContextTranslateCTM( aCopyContext.get(), 0, +mnHeight ); + CGContextScaleCTM( aCopyContext.get(), +1, -1 ); + } + + // TODO: pSrc->size() != this->size() + CGContextDrawLayerAtPoint(aCopyContext.get(), aDstPoint, pSrc->maLayer.get()); + + aCopyContext.restoreState(); + // mark the destination rectangle as updated + RefreshRect( aDstRect ); + } + else + { + std::shared_ptr pBitmap = pSrc->getBitmap( rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ); + if( pBitmap ) + { + SalTwoRect aPosAry( rPosAry ); + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + drawBitmap( aPosAry, *pBitmap ); + } + } +} + +static void DrawPattern50( void*, CGContextRef rContext ) +{ + static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } }; + CGContextAddRects( rContext, aRects, 2 ); + CGContextFillPath( rContext ); +} + +static void getBoundRect( sal_uInt32 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( sal_uInt32 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 Color ImplGetROPColor( SalROPColor nROPColor ) +{ + Color nColor; + if ( nROPColor == SalROPColor::N0 ) + { + nColor = Color( 0, 0, 0 ); + } + else + { + nColor = Color( 255, 255, 255 ); + } + return nColor; +} + +// 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 + } +} + +void AquaSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, bool /*bWindowInvalidate*/ ) +{ + SAL_WARN_IF (!maLayer.isSet(), "vcl.quartz", + "AquaSalGraphics::copyArea() for non-layered graphics this=" << this); + +#ifdef IOS + if (!maLayer.isSet()) + return; +#endif + float fScale = maLayer.getScale(); + + long nScaledSourceX = nSrcX * fScale; + long nScaledSourceY = nSrcY * fScale; + + long nScaledTargetX = nDstX * fScale; + long nScaledTargetY = nDstY * fScale; + + long nScaledSourceWidth = nSrcWidth * fScale; + long nScaledSourceHeight = nSrcHeight * fScale; + + ApplyXorContext(); + + maContextHolder.saveState(); + + // in XOR mode the drawing context is redirected to the XOR mask + // copyArea() always works on the target context though + CGContextRef xCopyContext = maContextHolder.get(); + + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + xCopyContext = mpXorEmulation->GetTargetContext(); + } + + // If we have a scaled layer, we need to revert the scaling or else + // it will interfere with the coordinate calculation + CGContextScaleCTM(xCopyContext, 1.0 / fScale, 1.0 / fScale); + + // 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 + + CGLayerHolder sSourceLayerHolder(maLayer); + { + const CGSize aSrcSize = CGSizeMake(nScaledSourceWidth, nScaledSourceHeight); + sSourceLayerHolder.set(CGLayerCreateWithContext(xCopyContext, aSrcSize, nullptr)); + + const CGContextRef xSrcContext = CGLayerGetContext(sSourceLayerHolder.get()); + + CGPoint aSrcPoint = CGPointMake(-nScaledSourceX, -nScaledSourceY); + if( IsFlipped() ) + { + CGContextTranslateCTM( xSrcContext, 0, +nScaledSourceHeight ); + CGContextScaleCTM( xSrcContext, +1, -1 ); + aSrcPoint.y = (nScaledSourceY + nScaledSourceHeight) - (mnHeight * fScale); + } + CGContextSetBlendMode(xSrcContext, kCGBlendModeCopy); + + CGContextDrawLayerAtPoint(xSrcContext, aSrcPoint, maLayer.get()); + } + + // draw at new destination + const CGRect aTargetRect = CGRectMake(nScaledTargetX, nScaledTargetY, nScaledSourceWidth, nScaledSourceHeight); + CGContextSetBlendMode(xCopyContext, kCGBlendModeCopy); + CGContextDrawLayerInRect(xCopyContext, aTargetRect, sSourceLayerHolder.get()); + + maContextHolder.restoreState(); + + // cleanup + if (sSourceLayerHolder.get() != maLayer.get()) + { + CGLayerRelease(sSourceLayerHolder.get()); + } + // mark the destination rectangle as updated + RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight ); +} + +#ifndef IOS + +void AquaSalGraphics::copyResolution( AquaSalGraphics& rGraphics ) +{ + if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame ) + { + rGraphics.initResolution( rGraphics.mpFrame->getNSWindow() ); + } + mnRealDPIX = rGraphics.mnRealDPIX; + mnRealDPIY = rGraphics.mnRealDPIY; +} + +#endif + +bool AquaSalGraphics::blendBitmap( const SalTwoRect&, + const SalBitmap& ) +{ + return false; +} + +bool AquaSalGraphics::blendAlphaBitmap( const SalTwoRect&, + const SalBitmap&, + const SalBitmap&, + const SalBitmap& ) +{ + return false; +} + +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 QuartzSalBitmap& rSrcSalBmp = static_cast(rSrcBitmap); + const QuartzSalBitmap& rMaskSalBmp = static_cast(rAlphaBmp); + CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, + rTR.mnSrcY, rTR.mnSrcWidth, + rTR.mnSrcHeight ); + if( !xMaskedImage ) + return false; + + if ( CheckContext() ) + { + const CGRect aDstRect = CGRectMake( rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight); + CGContextDrawImage( maContextHolder.get(), aDstRect, xMaskedImage ); + RefreshRect( aDstRect ); + } + + CGImageRelease(xMaskedImage); + + return true; +} + +bool AquaSalGraphics::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, + const SalBitmap& rSrcBitmap, const SalBitmap* pAlphaBmp ) +{ + if( !CheckContext() ) + return true; + + // get the Quartz image + CGImageRef xImage = nullptr; + const Size aSize = rSrcBitmap.GetSize(); + const QuartzSalBitmap& rSrcSalBmp = static_cast(rSrcBitmap); + const QuartzSalBitmap* pMaskSalBmp = static_cast(pAlphaBmp); + + if( !pMaskSalBmp) + xImage = rSrcSalBmp.CreateCroppedImage( 0, 0, static_cast(aSize.Width()), static_cast(aSize.Height()) ); + else + xImage = rSrcSalBmp.CreateWithMask( *pMaskSalBmp, 0, 0, static_cast(aSize.Width()), static_cast(aSize.Height()) ); + if( !xImage ) + return false; + + // setup the image transformation + // using the rNull,rX,rY points as destinations for the (0,0),(0,Width),(Height,0) source points + maContextHolder.saveState(); + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + const CGAffineTransform aCGMat = CGAffineTransformMake( + aXRel.getX()/aSize.Width(), aXRel.getY()/aSize.Width(), + aYRel.getX()/aSize.Height(), aYRel.getY()/aSize.Height(), + rNull.getX(), rNull.getY()); + + CGContextConcatCTM( maContextHolder.get(), aCGMat ); + + // draw the transformed image + const CGRect aSrcRect = CGRectMake(0, 0, aSize.Width(), aSize.Height()); + CGContextDrawImage( maContextHolder.get(), aSrcRect, xImage ); + + CGImageRelease( xImage ); + // restore the Quartz graphics state + maContextHolder.restoreState(); + + // mark the destination as painted + const CGRect aDstRect = CGRectApplyAffineTransform( aSrcRect, aCGMat ); + RefreshRect( aDstRect ); + + return true; +} + +bool AquaSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( !CheckContext() ) + return true; + + // save the current state + maContextHolder.saveState(); + CGContextSetAlpha( maContextHolder.get(), (100-nTransparency) * (1.0/100) ); + + CGRect aRect = CGRectMake(nX, nY, nWidth-1, nHeight-1); + if( IsPenVisible() ) + { + aRect.origin.x += 0.5; + aRect.origin.y += 0.5; + } + + CGContextBeginPath( maContextHolder.get() ); + CGContextAddRect( maContextHolder.get(), aRect ); + CGContextDrawPath( maContextHolder.get(), kCGPathFill ); + + maContextHolder.restoreState(); + RefreshRect( aRect ); + + return true; +} + +void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) +{ + if( !CheckContext() ) + return; + + const QuartzSalBitmap& rBitmap = static_cast(rSalBitmap); + CGImageRef xImage = rBitmap.CreateCroppedImage( static_cast(rPosAry.mnSrcX), static_cast(rPosAry.mnSrcY), + static_cast(rPosAry.mnSrcWidth), static_cast(rPosAry.mnSrcHeight) ); + if( !xImage ) + return; + + const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + CGContextDrawImage( maContextHolder.get(), aDstRect, xImage ); + + CGImageRelease( xImage ); + RefreshRect( aDstRect ); +} + +void AquaSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) +{ + if( !CheckContext() ) + return; + + const QuartzSalBitmap& rBitmap = static_cast(rSalBitmap); + const QuartzSalBitmap& rMask = static_cast(rTransparentBitmap); + CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight ) ); + if( !xMaskedImage ) + return; + + const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + CGContextDrawImage( maContextHolder.get(), aDstRect, xMaskedImage ); + CGImageRelease( xMaskedImage ); + RefreshRect( aDstRect ); +} + +#ifndef IOS + +bool AquaSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, + void* pEpsData, sal_uInt32 nByteCount ) +{ + // convert the raw data to an NSImageRef + NSData* xNSData = [NSData dataWithBytes:pEpsData length:static_cast(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 + maContextHolder.saveState(); +// CGContextTranslateCTM( maContextHolder.get(), 0, +mnHeight ); + CGContextScaleCTM( maContextHolder.get(), +1, -1 ); + nY = /*mnHeight*/ - (nY + nHeight); + + // prepare the target context + NSGraphicsContext* pOrigNSCtx = [NSGraphicsContext currentContext]; + [pOrigNSCtx retain]; + + // create new context + NSGraphicsContext* pDrawNSCtx = [NSGraphicsContext graphicsContextWithCGContext: maContextHolder.get() flipped: IsFlipped()]; + // set it, setCurrentContext also releases the previously set one + [NSGraphicsContext setCurrentContext: pDrawNSCtx]; + + // draw the EPS + const NSRect aDstRect = NSMakeRect( nX, nY, nWidth, nHeight); + const bool bOK = [xEpsImage drawInRect: aDstRect]; + + // restore the NSGraphicsContext + [NSGraphicsContext setCurrentContext: pOrigNSCtx]; + [pOrigNSCtx release]; // restore the original retain count + + maContextHolder.restoreState(); + // mark the destination rectangle as updated + RefreshRect( aDstRect ); + + return bOK; +} + +#endif + +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( maContextHolder.get() ); + CGContextMoveToPoint( maContextHolder.get(), static_cast(nX1)+0.5, static_cast(nY1)+0.5 ); + CGContextAddLineToPoint( maContextHolder.get(), static_cast(nX2)+0.5, static_cast(nY2)+0.5 ); + CGContextDrawPath( maContextHolder.get(), kCGPathStroke ); + + tools::Rectangle aRefreshRect( nX1, nY1, nX2, nY2 ); + (void) aRefreshRect; + // Is a call to RefreshRect( aRefreshRect ) missing here? +} + +void AquaSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, Color nMaskColor ) +{ + if( !CheckContext() ) + return; + + const QuartzSalBitmap& rBitmap = static_cast(rSalBitmap); + CGImageRef xImage = rBitmap.CreateColorMask( rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + nMaskColor ); + if( !xImage ) + return; + + const CGRect aDstRect = CGRectMake(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight); + CGContextDrawImage( maContextHolder.get(), aDstRect, xImage ); + CGImageRelease( xImage ); + RefreshRect( aDstRect ); +} + +void AquaSalGraphics::drawPixel( long nX, long nY ) +{ + // draw pixel with current line color + ImplDrawPixel( nX, nY, maLineColor ); +} + +void AquaSalGraphics::drawPixel( long nX, long nY, Color nColor ) +{ + const RGBAColor aPixelColor( nColor ); + ImplDrawPixel( nX, nY, aPixelColor ); +} + +bool AquaSalGraphics::drawPolyLine( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, + double fTransparency, + double fLineWidth, + const std::vector< double >* pStroke, // MM01 + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, + double fMiterMinimumAngle, + bool bPixelSnapHairline) +{ + // MM01 check done for simple reasons + if(!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0) + { + return true; + } + +#ifdef IOS + if( !CheckContext() ) + return false; +#endif + + // tdf#124848 get correct LineWidth in discrete coordinates, + if(fLineWidth == 0) // hairline + fLineWidth = 1.0; + else // Adjust line width for object-to-device scale. + fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); + + // #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) && (fLineWidth > 1.3) ) + return false; + + // MM01 need to do line dashing as fallback stuff here now + const double fDotDashLength(nullptr != pStroke ? std::accumulate(pStroke->begin(), pStroke->end(), 0.0) : 0.0); + const bool bStrokeUsed(0.0 != fDotDashLength); + assert(!bStrokeUsed || (bStrokeUsed && pStroke)); + basegfx::B2DPolyPolygon aPolyPolygonLine; + + if(bStrokeUsed) + { + // apply LineStyle + basegfx::utils::applyLineDashing( + rPolyLine, // source + *pStroke, // pattern + &aPolyPolygonLine, // target for lines + nullptr, // target for gaps + fDotDashLength); // full length if available + } + else + { + // no line dashing, just copy + aPolyPolygonLine.append(rPolyLine); + } + + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline + aPolyPolygonLine.transform(rObjectToDevice); + if(bPixelSnapHairline) { aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); } + + // setup line attributes + CGLineJoin aCGLineJoin = kCGLineJoinMiter; + switch( eLineJoin ) + { + case basegfx::B2DLineJoin::NONE: 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; + } + // convert miter minimum angle to miter limit + CGFloat fCGMiterLimit = 1.0 / sin(fMiterMinimumAngle / 2.0); + // setup cap attribute + CGLineCap aCGLineCap(kCGLineCapButt); + + switch(eLineCap) + { + default: // css::drawing::LineCap_BUTT: + { + aCGLineCap = kCGLineCapButt; + break; + } + case css::drawing::LineCap_ROUND: + { + aCGLineCap = kCGLineCapRound; + break; + } + case css::drawing::LineCap_SQUARE: + { + aCGLineCap = kCGLineCapSquare; + break; + } + } + + // setup poly-polygon path + CGMutablePathRef xPath = CGPathCreateMutable(); + + // MM01 todo - I assume that this is OKAY to be done in one run for quartz + // but this NEEDS to be checked/verified + for(sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + { + const basegfx::B2DPolygon aPolyLine(aPolyPolygonLine.getB2DPolygon(a)); + AddPolygonToPath( + xPath, + aPolyLine, + aPolyLine.isClosed(), + !getAntiAliasB2DDraw(), + true); + } + + const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); + // #i97317# workaround for Quartz having problems with drawing small polygons + if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) + { + // use the path to prepare the graphics context + maContextHolder.saveState(); + CGContextBeginPath( maContextHolder.get() ); + CGContextAddPath( maContextHolder.get(), xPath ); + // draw path with antialiased line + CGContextSetShouldAntialias( maContextHolder.get(), true ); + CGContextSetAlpha( maContextHolder.get(), 1.0 - fTransparency ); + CGContextSetLineJoin( maContextHolder.get(), aCGLineJoin ); + CGContextSetLineCap( maContextHolder.get(), aCGLineCap ); + CGContextSetLineWidth( maContextHolder.get(), fLineWidth ); + CGContextSetMiterLimit(maContextHolder.get(), fCGMiterLimit); + CGContextDrawPath( maContextHolder.get(), kCGPathStroke ); + maContextHolder.restoreState(); + + // mark modified rectangle as updated + RefreshRect( aRefreshRect ); + } + + CGPathRelease( xPath ); + + return true; +} + +bool AquaSalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const PolyFlags* ) +{ + return false; +} + +bool AquaSalGraphics::drawPolyPolygon( + const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ +#ifdef IOS + if (!maContextHolder.isSet()) + return true; +#endif + + // short circuit if there is nothing to do + if( rPolyPolygon.count() == 0 ) + return true; + + // ignore invisible polygons + if( (fTransparency >= 1.0) || (fTransparency < 0) ) + return true; + + // Fallback: Transform to DeviceCoordinates + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + // setup poly-polygon path + CGMutablePathRef xPath = CGPathCreateMutable(); + // tdf#120252 Use the correct, already transformed PolyPolygon (as long as + // the transformation is not used here...) + for(auto const& rPolygon : aPolyPolygon) + { + AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() ); + } + + const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); + // #i97317# workaround for Quartz having problems with drawing small polygons + if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) + { + // prepare drawing mode + CGPathDrawingMode eMode; + if( IsBrushVisible() && IsPenVisible() ) + { + eMode = kCGPathEOFillStroke; + } + else if( IsPenVisible() ) + { + eMode = kCGPathStroke; + } + else if( IsBrushVisible() ) + { + eMode = kCGPathEOFill; + } + else + { + SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); + CGPathRelease( xPath ); + return true; + } + + // use the path to prepare the graphics context + maContextHolder.saveState(); + CGContextBeginPath( maContextHolder.get() ); + CGContextAddPath( maContextHolder.get(), xPath ); + + // draw path with antialiased polygon + CGContextSetShouldAntialias( maContextHolder.get(), true ); + CGContextSetAlpha( maContextHolder.get(), 1.0 - fTransparency ); + CGContextDrawPath( maContextHolder.get(), eMode ); + maContextHolder.restoreState(); + + // mark modified rectangle as updated + RefreshRect( aRefreshRect ); + } + + CGPathRelease( xPath ); + + return true; +} + +void AquaSalGraphics::drawPolyPolygon( sal_uInt32 nPolyCount, const sal_uInt32 *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( sal_uInt32 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 + { + SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); + return; + } + + // convert to CGPath + CGContextBeginPath( maContextHolder.get() ); + if( IsPenVisible() ) + { + for( sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + const sal_uInt32 nPoints = pPoints[nPoly]; + if( nPoints > 1 ) + { + const SalPoint *pPtAry = ppPtAry[nPoly]; + float fX, fY; + + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( maContextHolder.get(), fX, fY ); + pPtAry++; + + for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( maContextHolder.get(), fX, fY ); + } + CGContextClosePath(maContextHolder.get()); + } + } + } + else + { + for( sal_uInt32 nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + const sal_uInt32 nPoints = pPoints[nPoly]; + if( nPoints > 1 ) + { + const SalPoint *pPtAry = ppPtAry[nPoly]; + CGContextMoveToPoint( maContextHolder.get(), pPtAry->mnX, pPtAry->mnY ); + pPtAry++; + for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + CGContextAddLineToPoint( maContextHolder.get(), pPtAry->mnX, pPtAry->mnY ); + } + CGContextClosePath(maContextHolder.get()); + } + } + } + + CGContextDrawPath( maContextHolder.get(), eMode ); + + RefreshRect( leftX, topY, maxWidth, maxHeight ); +} + +void AquaSalGraphics::drawPolygon( sal_uInt32 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 + { + SAL_WARN( "vcl.quartz", "Neither pen nor brush visible" ); + return; + } + + CGContextBeginPath( maContextHolder.get() ); + + if( IsPenVisible() ) + { + float fX, fY; + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( maContextHolder.get(), fX, fY ); + pPtAry++; + for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( maContextHolder.get(), fX, fY ); + } + } + else + { + CGContextMoveToPoint( maContextHolder.get(), pPtAry->mnX, pPtAry->mnY ); + pPtAry++; + for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + CGContextAddLineToPoint( maContextHolder.get(), pPtAry->mnX, pPtAry->mnY ); + } + } + + CGContextClosePath( maContextHolder.get() ); + CGContextDrawPath( maContextHolder.get(), eMode ); + RefreshRect( nX, nY, nWidth, nHeight ); +} + +bool AquaSalGraphics::drawPolygonBezier( sal_uInt32, const SalPoint*, const PolyFlags* ) +{ + return false; +} + +bool AquaSalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*, + const SalPoint* const*, const PolyFlags* const* ) +{ + return false; +} + +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( maContextHolder.get(), aRect ); + } + if( IsPenVisible() ) + { + CGContextStrokeRect( maContextHolder.get(), aRect ); + } + RefreshRect( nX, nY, nWidth, nHeight ); +} + +void AquaSalGraphics::drawPolyLine( sal_uInt32 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( maContextHolder.get() ); + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( maContextHolder.get(), fX, fY ); + pPtAry++; + + for( sal_uInt32 nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( maContextHolder.get(), fX, fY ); + } + CGContextStrokePath(maContextHolder.get()); + + RefreshRect( nX, nY, nWidth, nHeight ); +} + +sal_uInt16 AquaSalGraphics::GetBitCount() const +{ + sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24; + return nBits; +} + +std::shared_ptr AquaSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + SAL_WARN_IF(!maLayer.isSet(), "vcl.quartz", "AquaSalGraphics::getBitmap() with no layer this=" << this); + + ApplyXorContext(); + + std::shared_ptr pBitmap = std::make_shared(); + if (!pBitmap->Create(maLayer, mnBitmapDepth, nX, nY, nDX, nDY, IsFlipped())) + { + pBitmap = nullptr; + } + return pBitmap; +} + +SystemGraphicsData AquaSalGraphics::GetGraphicsData() const +{ + SystemGraphicsData aRes; + aRes.nSize = sizeof(aRes); + aRes.rCGContext = maContextHolder.get(); + return aRes; +} + +long AquaSalGraphics::GetGraphicsWidth() const +{ + long w = 0; + if( maContextHolder.isSet() && ( +#ifndef IOS + mbWindow || +#endif + mbVirDev) ) + { + w = mnWidth; + } + +#ifndef IOS + if( w == 0 ) + { + if( mbWindow && mpFrame ) + { + w = mpFrame->maGeometry.nWidth; + } + } +#endif + return w; +} + +Color AquaSalGraphics::getPixel( long nX, long nY ) +{ + // return default value on printers or when out of bounds + if (!maLayer.isSet() || (nX < 0) || (nX >= mnWidth) || + (nY < 0) || (nY >= mnHeight)) + { + return sal_uInt32(COL_BLACK); + } + // prepare creation of matching a CGBitmapContext +#if defined OSL_BIGENDIAN + 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, 32, + GetSalData()->mxRGBSpace, + uint32_t(kCGImageAlphaNoneSkipFirst) | uint32_t(kCGBitmapByteOrder32Big) ); + + // update this graphics layer + ApplyXorContext(); + + // copy the requested pixel into the bitmap context + if( IsFlipped() ) + { + nY = mnHeight - nY; + } + const CGPoint aCGPoint = CGPointMake(-nX, -nY); + CGContextDrawLayerAtPoint(xOnePixelContext, aCGPoint, maLayer.get()); + + CGContextRelease( xOnePixelContext ); + + Color nColor( aPixel.r, aPixel.g, aPixel.b ); + return nColor; +} + +void AquaSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) +{ +#ifndef IOS + if( !mnRealDPIY ) + { + initResolution( (mbWindow && mpFrame) ? mpFrame->getNSWindow() : nil ); + } + + rDPIX = mnRealDPIX; + rDPIY = mnRealDPIY; +#else + // This *must* be 96 or else the iOS app will behave very badly (tiles are scaled wrongly and + // don't match each others at their boundaries, and other issues). But *why* it must be 96 I + // have no idea. The commit that changed it to 96 from (the arbitrary) 200 did not say. If you + // know where else 96 is explicitly or implicitly hard-coded, please modify this comment. + + // Follow-up: It might be this: in 'online', loleaflet/src/map/Map.js: + // 15 = 1440 twips-per-inch / 96 dpi. + // Chosen to match previous hardcoded value of 3840 for + // the current tile pixel size of 256. + rDPIX = rDPIY = 96; +#endif +} + +void AquaSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor ) +{ + if( !CheckContext() ) + { + return; + } + // overwrite the fill color + CGContextSetFillColor( maContextHolder.get(), rColor.AsArray() ); + // draw 1x1 rect, there is no pixel drawing in Quartz + const CGRect aDstRect = CGRectMake(nX, nY, 1, 1); + CGContextFillRect( maContextHolder.get(), aDstRect ); + RefreshRect( aDstRect ); + // reset the fill color + CGContextSetFillColor( maContextHolder.get(), maFillColor.AsArray() ); +} + +#ifndef IOS + +void AquaSalGraphics::initResolution(NSWindow* nsWindow) +{ + if (!nsWindow) + { + if (Application::IsBitmapRendering()) + mnRealDPIX = mnRealDPIY = 96; + return; + } + + // #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 && [pScreens count] > 0) + { + 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 = static_cast([pVal longValue]); + const CGSize aSize = CGDisplayScreenSize( nDisplayID ); // => result is in millimeters + mnRealDPIX = static_cast((CGDisplayPixelsWide( nDisplayID ) * 25.4) / aSize.width); + mnRealDPIY = static_cast((CGDisplayPixelsHigh( nDisplayID ) * 25.4) / aSize.height); + } + else + { + OSL_FAIL( "no resolution found in device description" ); + } + } + else + { + OSL_FAIL( "no device description" ); + } + } + else + { + OSL_FAIL( "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; + } + // Note that on a Retina display, the "mnRealDPIX" as + // calculated above is not the true resolution of the display, + // but the "logical" one, or whatever the correct terminology + // is. (For instance on a 5K 27in iMac, it's 108.) So at + // least currently, it won't be over 200. I don't know whether + // this test is a "sanity check", or whether there is some + // real reason to limit this to 200. + 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; + } +} + +#endif + +void AquaSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) +{ + if ( CheckContext() ) + { + CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight); + maContextHolder.saveState(); + if ( nFlags & SalInvert::TrackFrame ) + { + const CGFloat dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line + CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference ); + CGContextSetRGBStrokeColor ( maContextHolder.get(), 1.0, 1.0, 1.0, 1.0 ); + CGContextSetLineDash ( maContextHolder.get(), 0, dashLengths, 2 ); + CGContextSetLineWidth( maContextHolder.get(), 2.0); + CGContextStrokeRect ( maContextHolder.get(), aCGRect ); + } + else if ( nFlags & SalInvert::N50 ) + { + //CGContextSetAllowsAntialiasing( maContextHolder.get(), false ); + CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference); + CGContextAddRect( maContextHolder.get(), aCGRect ); + Pattern50Fill(); + } + else // just invert + { + CGContextSetBlendMode(maContextHolder.get(), kCGBlendModeDifference); + CGContextSetRGBFillColor ( maContextHolder.get(),1.0, 1.0, 1.0 , 1.0 ); + CGContextFillRect ( maContextHolder.get(), aCGRect ); + } + maContextHolder.restoreState(); + RefreshRect( aCGRect ); + } +} + +namespace { + +CGPoint* makeCGptArray(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + CGPoint *CGpoints = new CGPoint[nPoints]; + for(sal_uLong i=0;imxRGBSpace ); + static const CGPatternRef mxP50Pattern = CGPatternCreate( nullptr, CGRectMake( 0, 0, 4, 4 ), + CGAffineTransformIdentity, 4, 4, + kCGPatternTilingConstantSpacing, + false, &aCallback ); + SAL_WARN_IF( !maContextHolder.get(), "vcl.quartz", "maContextHolder.get() is NULL" ); + CGContextSetFillColorSpace( maContextHolder.get(), mxP50Space ); + CGContextSetFillPattern( maContextHolder.get(), mxP50Pattern, aFillCol ); + CGContextFillPath( maContextHolder.get() ); +} + +void AquaSalGraphics::ResetClipRegion() +{ + // release old path and indicate no clipping + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = nullptr; + } + if( CheckContext() ) + { + SetState(); + } +} + +void AquaSalGraphics::SetState() +{ + maContextHolder.restoreState(); + maContextHolder.saveState(); + + // setup clipping + if( mxClipPath ) + { + CGContextBeginPath( maContextHolder.get() ); // discard any existing path + CGContextAddPath( maContextHolder.get(), mxClipPath ); // set the current path to the clipping path + CGContextClip( maContextHolder.get() ); // use it for clipping + } + + // set RGB colorspace and line and fill colors + CGContextSetFillColor( maContextHolder.get(), maFillColor.AsArray() ); + + CGContextSetStrokeColor( maContextHolder.get(), maLineColor.AsArray() ); + CGContextSetShouldAntialias( maContextHolder.get(), false ); + if( mnXorMode == 2 ) + { + CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference ); + } +} + +void AquaSalGraphics::SetLineColor() +{ + maLineColor.SetAlpha( 0.0 ); // transparent + if( CheckContext() ) + { + CGContextSetRGBStrokeColor( maContextHolder.get(), maLineColor.GetRed(), maLineColor.GetGreen(), + maLineColor.GetBlue(), maLineColor.GetAlpha() ); + } +} + +void AquaSalGraphics::SetLineColor( Color nColor ) +{ + maLineColor = RGBAColor( nColor ); + if( CheckContext() ) + { + CGContextSetRGBStrokeColor( maContextHolder.get(), maLineColor.GetRed(), maLineColor.GetGreen(), + maLineColor.GetBlue(), maLineColor.GetAlpha() ); + } +} + +void AquaSalGraphics::SetFillColor() +{ + maFillColor.SetAlpha( 0.0 ); // transparent + if( CheckContext() ) + { + CGContextSetRGBFillColor( maContextHolder.get(), maFillColor.GetRed(), maFillColor.GetGreen(), + maFillColor.GetBlue(), maFillColor.GetAlpha() ); + } +} + +void AquaSalGraphics::SetFillColor( Color nColor ) +{ + maFillColor = RGBAColor( nColor ); + if( CheckContext() ) + { + CGContextSetRGBFillColor( maContextHolder.get(), maFillColor.GetRed(), maFillColor.GetGreen(), + maFillColor.GetBlue(), maFillColor.GetAlpha() ); + } +} + +bool AquaSalGraphics::supportsOperation( OutDevSupportType eType ) const +{ + bool bRet = false; + switch( eType ) + { + case OutDevSupportType::TransparentRect: + case OutDevSupportType::B2DDraw: + bRet = true; + break; + default: + break; + } + return bRet; +} + +bool AquaSalGraphics::setClipRegion( const vcl::Region& i_rClip ) +{ + // release old clip path + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = nullptr; + } + mxClipPath = CGPathCreateMutable(); + + // set current path, either as polypolgon or sequence of rectangles + if(i_rClip.HasPolyPolygonOrB2DPolyPolygon()) + { + const basegfx::B2DPolyPolygon aClip(i_rClip.GetAsB2DPolyPolygon()); + + AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false ); + } + else + { + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + for(const auto& rRect : aRectangles) + { + const long nW(rRect.Right() - rRect.Left() + 1); // uses +1 logic in original + + if(nW) + { + const long nH(rRect.Bottom() - rRect.Top() + 1); // uses +1 logic in original + + if(nH) + { + const CGRect aRect = CGRectMake( rRect.Left(), rRect.Top(), nW, nH); + CGPathAddRect( mxClipPath, nullptr, aRect ); + } + } + } + } + // set the current path as clip region + if( CheckContext() ) + { + SetState(); + } + return true; +} + +void AquaSalGraphics::SetROPFillColor( SalROPColor nROPColor ) +{ + if( ! mbPrinter ) + { + SetFillColor( ImplGetROPColor( nROPColor ) ); + } +} + +void AquaSalGraphics::SetROPLineColor( SalROPColor nROPColor ) +{ + if( ! mbPrinter ) + { + SetLineColor( ImplGetROPColor( nROPColor ) ); + } +} + +void AquaSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) +{ + // return early if XOR mode remains unchanged + if( mbPrinter ) + { + return; + } + if( ! bSet && mnXorMode == 2 ) + { + CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeNormal ); + mnXorMode = 0; + return; + } + else if( bSet && bInvertOnly && mnXorMode == 0) + { + CGContextSetBlendMode( maContextHolder.get(), kCGBlendModeDifference ); + mnXorMode = 2; + return; + } + + if( (mpXorEmulation == nullptr) && !bSet ) + { + return; + } + if( (mpXorEmulation != nullptr) && (bSet == mpXorEmulation->IsEnabled()) ) + { + return; + } + if( !CheckContext() ) + { + return; + } + // prepare XOR emulation + if( !mpXorEmulation ) + { + mpXorEmulation = new XorEmulation(); + mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); + } + + // change the XOR mode + if( bSet ) + { + mpXorEmulation->Enable(); + maContextHolder.set(mpXorEmulation->GetMaskContext()); + mnXorMode = 1; + } + else + { + mpXorEmulation->UpdateTarget(); + mpXorEmulation->Disable(); + maContextHolder.set(mpXorEmulation->GetTargetContext()); + mnXorMode = 0; + } +} + +#ifndef IOS + +void AquaSalGraphics::updateResolution() +{ + SAL_WARN_IF( !mbWindow, "vcl", "updateResolution on inappropriate graphics" ); + + initResolution( (mbWindow && mpFrame) ? mpFrame->getNSWindow() : nil ); +} + +#endif + +XorEmulation::XorEmulation() + : m_xTargetLayer( nullptr ) + , m_xTargetContext( nullptr ) + , m_xMaskContext( nullptr ) + , m_xTempContext( nullptr ) + , m_pMaskBuffer( nullptr ) + , m_pTempBuffer( nullptr ) + , m_nBufferLongs( 0 ) + , m_bIsEnabled( false ) +{ + SAL_INFO( "vcl.quartz", "XorEmulation::XorEmulation() this=" << this ); +} + +XorEmulation::~XorEmulation() +{ + SAL_INFO( "vcl.quartz", "XorEmulation::~XorEmulation() this=" << this ); + Disable(); + SetTarget( 0, 0, 0, nullptr, nullptr ); +} + +void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth, + CGContextRef xTargetContext, CGLayerRef xTargetLayer ) +{ + SAL_INFO( "vcl.quartz", "XorEmulation::SetTarget() this=" << this << + " (" << nWidth << "x" << nHeight << ") depth=" << nTargetDepth << + " context=" << xTargetContext << " layer=" << xTargetLayer ); + + // prepare to replace old mask+temp context + if( m_xMaskContext ) + { + // cleanup the mask context + CGContextRelease( m_xMaskContext ); + delete[] m_pMaskBuffer; + m_xMaskContext = nullptr; + m_pMaskBuffer = nullptr; + + // cleanup the temp context if needed + if( m_xTempContext ) + { + CGContextRelease( m_xTempContext ); + delete[] m_pTempBuffer; + m_xTempContext = nullptr; + m_pTempBuffer = nullptr; + } + } + + // return early if there is nothing more to do + if( !xTargetContext ) + { + return; + } + // retarget drawing operations to the XOR mask + m_xTargetLayer = xTargetLayer; + m_xTargetContext = xTargetContext; + + // prepare creation of matching CGBitmaps + CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; + CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; + int nBitDepth = nTargetDepth; + if( !nBitDepth ) + { + nBitDepth = 32; + } + int nBytesPerRow = 4; + const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8; + if( nBitDepth <= 8 ) + { + aCGColorSpace = GetSalData()->mxGraySpace; + aCGBmpInfo = kCGImageAlphaNone; + nBytesPerRow = 1; + } + nBytesPerRow *= nWidth; + m_nBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong); + + // create a XorMask context + m_pMaskBuffer = new sal_uLong[ m_nBufferLongs ]; + m_xMaskContext = CGBitmapContextCreate( m_pMaskBuffer, + nWidth, nHeight, + nBitsPerComponent, nBytesPerRow, + aCGColorSpace, aCGBmpInfo ); + SAL_WARN_IF( !m_xMaskContext, "vcl.quartz", "mask context creation failed" ); + + // reset the XOR mask to black + memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) ); + + // a bitmap context will be needed for manual XORing + // create one unless the target context is a bitmap context + if( nTargetDepth ) + { + m_pTempBuffer = static_cast(CGBitmapContextGetData( m_xTargetContext )); + } + if( !m_pTempBuffer ) + { + // create a bitmap context matching to the target context + m_pTempBuffer = new sal_uLong[ m_nBufferLongs ]; + m_xTempContext = CGBitmapContextCreate( m_pTempBuffer, + nWidth, nHeight, + nBitsPerComponent, nBytesPerRow, + aCGColorSpace, aCGBmpInfo ); + SAL_WARN_IF( !m_xTempContext, "vcl.quartz", "temp context creation failed" ); + } + + // initialize XOR mask context for drawing + CGContextSetFillColorSpace( m_xMaskContext, aCGColorSpace ); + CGContextSetStrokeColorSpace( m_xMaskContext, aCGColorSpace ); + CGContextSetShouldAntialias( m_xMaskContext, false ); + + // improve the XorMask's XOR emulation a little + // NOTE: currently only enabled for monochrome contexts + if( aCGColorSpace == GetSalData()->mxGraySpace ) + { + CGContextSetBlendMode( m_xMaskContext, kCGBlendModeDifference ); + } + // initialize the transformation matrix to the drawing target + const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext ); + CGContextConcatCTM( m_xMaskContext, aCTM ); + if( m_xTempContext ) + { + CGContextConcatCTM( m_xTempContext, aCTM ); + } + // initialize the default XorMask graphics state + CGContextSaveGState( m_xMaskContext ); +} + +bool XorEmulation::UpdateTarget() +{ + SAL_INFO( "vcl.quartz", "XorEmulation::UpdateTarget() this=" << this ); + + if( !IsEnabled() ) + { + return false; + } + // update the temp bitmap buffer if needed + if( m_xTempContext ) + { + SAL_WARN_IF( m_xTargetContext == nullptr, "vcl.quartz", "Target layer is NULL"); + CGContextDrawLayerAtPoint( m_xTempContext, CGPointZero, m_xTargetLayer ); + } + // 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 sal_uLong* pSrc = m_pMaskBuffer; + sal_uLong* pDst = m_pTempBuffer; + for( int i = m_nBufferLongs; --i >= 0;) + { + *(pDst++) ^= *(pSrc++); + } + // write back the XOR results to the target context + if( m_xTempContext ) + { + CGImageRef xXorImage = CGBitmapContextCreateImage( m_xTempContext ); + const int nWidth = static_cast(CGImageGetWidth( xXorImage )); + const int nHeight = static_cast(CGImageGetHeight( xXorImage )); + // TODO: update minimal changerect + const CGRect aFullRect = CGRectMake(0, 0, nWidth, nHeight); + CGContextDrawImage( m_xTargetContext, aFullRect, xXorImage ); + CGImageRelease( xXorImage ); + } + + // reset the XorMask to black again + // TODO: not needed for last update + memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) ); + + // TODO: return FALSE if target was not changed + return true; +} + +void AquaSalGraphics::SetVirDevGraphics(CGLayerHolder const & rLayer, CGContextRef xContext, + int nBitmapDepth) +{ + SAL_INFO( "vcl.quartz", "SetVirDevGraphics() this=" << this << " layer=" << rLayer.get() << " context=" << xContext ); + +#ifndef IOS + mbWindow = false; +#endif + mbPrinter = false; + mbVirDev = true; + + // set graphics properties + maLayer = rLayer; + maContextHolder.set(xContext); + + mnBitmapDepth = nBitmapDepth; + +#ifdef IOS + mbForeignContext = xContext != NULL; +#endif + + // return early if the virdev is being destroyed + if( !xContext ) + return; + + // get new graphics properties + if (!maLayer.isSet()) + { + mnWidth = CGBitmapContextGetWidth( maContextHolder.get() ); + mnHeight = CGBitmapContextGetHeight( maContextHolder.get() ); + } + else + { + const CGSize aSize = CGLayerGetSize(maLayer.get()); + mnWidth = static_cast(aSize.width); + mnHeight = static_cast(aSize.height); + } + + // prepare graphics for drawing + const CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; + CGContextSetFillColorSpace( maContextHolder.get(), aCGColorSpace ); + CGContextSetStrokeColorSpace( maContextHolder.get(), aCGColorSpace ); + + // re-enable XorEmulation for the new context + if( mpXorEmulation ) + { + mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); + if( mpXorEmulation->IsEnabled() ) + { + maContextHolder.set(mpXorEmulation->GetMaskContext()); + } + } + + // initialize stack of CGContext states + maContextHolder.saveState(); + SetState(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdiutils.cxx b/vcl/quartz/salgdiutils.cxx new file mode 100644 index 000000000..57953e536 --- /dev/null +++ b/vcl/quartz/salgdiutils.cxx @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +void AquaSalGraphics::SetWindowGraphics( AquaSalFrame* pFrame ) +{ + mpFrame = pFrame; + mbWindow = true; + mbPrinter = false; + mbVirDev = false; +} + +void AquaSalGraphics::SetPrinterGraphics( CGContextRef xContext, long nDPIX, long nDPIY ) +{ + mbWindow = false; + mbPrinter = true; + mbVirDev = false; + + maContextHolder.set(xContext); + mnRealDPIX = nDPIX; + mnRealDPIY = nDPIY; + + // a previously set clip path is now invalid + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = nullptr; + } + + if (maContextHolder.isSet()) + { + CGContextSetFillColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace ); + CGContextSetStrokeColorSpace( maContextHolder.get(), GetSalData()->mxRGBSpace ); + CGContextSaveGState( maContextHolder.get() ); + SetState(); + } +} + +void AquaSalGraphics::InvalidateContext() +{ + UnsetState(); + + CGContextRelease(maContextHolder.get()); + CGContextRelease(maBGContextHolder.get()); + CGContextRelease(maCSContextHolder.get()); + + maContextHolder.set(nullptr); + maCSContextHolder.set(nullptr); + maBGContextHolder.set(nullptr); +} + +void AquaSalGraphics::UnsetState() +{ + if (maBGContextHolder.isSet()) + { + CGContextRelease(maBGContextHolder.get()); + maBGContextHolder.set(nullptr); + } + if (maCSContextHolder.isSet()) + { + CGContextRelease(maCSContextHolder.get()); + maBGContextHolder.set(nullptr); + } + if (maContextHolder.isSet()) + { + maContextHolder.restoreState(); + maContextHolder.set(nullptr); + } + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = nullptr; + } +} + +/** + * (re-)create the off-screen maLayer we render everything to if + * necessary: eg. not initialized yet, or it has an incorrect size. + */ +bool AquaSalGraphics::CheckContext() +{ + if (mbWindow && mpFrame && (mpFrame->getNSWindow() || Application::IsBitmapRendering())) + { + const unsigned int nWidth = mpFrame->maGeometry.nWidth; + const unsigned int nHeight = mpFrame->maGeometry.nHeight; + + // Let's get the window scaling factor if possible, or use 1.0 + // as the scaling factor. + float fScale = 1.0f; + if (mpFrame->getNSWindow()) + fScale = [mpFrame->getNSWindow() backingScaleFactor]; + + CGLayerRef rReleaseLayer = nullptr; + + // 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 + if (maLayer.isSet()) + { + rReleaseLayer = maLayer.get(); + } + else if (maContextHolder.isSet()) + { + CGContextRelease(maContextHolder.get()); + } + CGContextRelease(maBGContextHolder.get()); + CGContextRelease(maCSContextHolder.get()); + + maContextHolder.set(nullptr); + maBGContextHolder.set(nullptr); + maCSContextHolder.set(nullptr); + maLayer.set(nullptr); + } + + if (!maContextHolder.isSet()) + { + const int nBitmapDepth = 32; + + float nScaledWidth = mnWidth * fScale; + float nScaledHeight = mnHeight * fScale; + + const CGSize aLayerSize = { static_cast(nScaledWidth), static_cast(nScaledHeight) }; + + const int nBytesPerRow = (nBitmapDepth * nScaledWidth) / 8; + int nFlags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + maBGContextHolder.set(CGBitmapContextCreate( + NULL, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags)); + + maLayer.set(CGLayerCreateWithContext(maBGContextHolder.get(), aLayerSize, nullptr)); + maLayer.setScale(fScale); + + nFlags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + maCSContextHolder.set(CGBitmapContextCreate( + NULL, nScaledWidth, nScaledHeight, 8, nBytesPerRow, GetSalData()->mxRGBSpace, nFlags)); + + CGContextRef xDrawContext = CGLayerGetContext(maLayer.get()); + maContextHolder = xDrawContext; + + if (rReleaseLayer) + { + // copy original layer to resized layer + if (maContextHolder.isSet()) + { + CGContextDrawLayerAtPoint(maContextHolder.get(), CGPointZero, rReleaseLayer); + } + CGLayerRelease(rReleaseLayer); + } + + if (maContextHolder.isSet()) + { + CGContextTranslateCTM(maContextHolder.get(), 0, nScaledHeight); + CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0); + CGContextSetFillColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace); + CGContextSetStrokeColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace); + // apply a scale matrix so everything is auto-magically scaled + CGContextScaleCTM(maContextHolder.get(), fScale, fScale); + maContextHolder.saveState(); + SetState(); + + // re-enable XOR emulation for the new context + if (mpXorEmulation) + mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get()); + } + } + } + + SAL_WARN_IF(!maContextHolder.isSet() && !mbPrinter, "vcl", "<<>> AquaSalGraphics::CheckContext() FAILED!!!!"); + + return maContextHolder.isSet(); +} + +CGContextRef AquaSalGraphics::GetContext() +{ + if (!maContextHolder.isSet()) + { + CheckContext(); + } + return maContextHolder.get(); +} + +/** + * Blit the contents of our internal maLayer state to the + * associated window, if any; cf. drawRect event handling + * on the frame. + */ +void AquaSalGraphics::UpdateWindow( NSRect& ) +{ + if( !mpFrame ) + { + return; + } + + NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; + if (maLayer.isSet() && pContext != nullptr) + { + CGContextHolder rCGContextHolder([pContext CGContext]); + + rCGContextHolder.saveState(); + + CGMutablePathRef rClip = mpFrame->getClipPath(); + if (rClip) + { + CGContextBeginPath(rCGContextHolder.get()); + CGContextAddPath(rCGContextHolder.get(), rClip ); + CGContextClip(rCGContextHolder.get()); + } + + ApplyXorContext(); + + const CGSize aSize = maLayer.getSizePoints(); + const CGRect aRect = CGRectMake(0, 0, aSize.width, aSize.height); + const CGRect aRectPoints = { CGPointZero, maLayer.getSizePixels() }; + CGContextSetBlendMode(maCSContextHolder.get(), kCGBlendModeCopy); + CGContextDrawLayerInRect(maCSContextHolder.get(), aRectPoints, maLayer.get()); + + CGImageRef img = CGBitmapContextCreateImage(maCSContextHolder.get()); + CGImageRef displayColorSpaceImage = CGImageCreateCopyWithColorSpace(img, [[mpFrame->getNSWindow() colorSpace] CGColorSpace]); + CGContextSetBlendMode(rCGContextHolder.get(), kCGBlendModeCopy); + CGContextDrawImage(rCGContextHolder.get(), aRect, displayColorSpaceImage); + + CGImageRelease(img); + CGImageRelease(displayColorSpaceImage); + + rCGContextHolder.restoreState(); + } + else + { + SAL_WARN_IF( !mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics" ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salvd.cxx b/vcl/quartz/salvd.cxx new file mode 100644 index 000000000..c06ba33c5 --- /dev/null +++ b/vcl/quartz/salvd.cxx @@ -0,0 +1,303 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#ifdef MACOSX +#include +#include +#include +#else +#include "headless/svpframe.hxx" +#include "headless/svpinst.hxx" +#include "headless/svpvd.hxx" +#endif +#include +#include +#include + +std::unique_ptr AquaSalInstance::CreateVirtualDevice( SalGraphics* pGraphics, + long &nDX, long &nDY, + DeviceFormat eFormat, + const SystemGraphicsData *pData ) +{ + // #i92075# can be called first in a thread + SalData::ensureThreadAutoreleasePool(); + +#ifdef IOS + if( pData ) + { + return std::unique_ptr(new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), + nDX, nDY, eFormat, pData )); + } + else + { + std::unique_ptr pNew(new AquaSalVirtualDevice( NULL, nDX, nDY, eFormat, NULL )); + pNew->SetSize( nDX, nDY ); + return pNew; + } +#else + return std::unique_ptr(new AquaSalVirtualDevice( static_cast< AquaSalGraphics* >( pGraphics ), + nDX, nDY, eFormat, pData )); +#endif +} + +AquaSalVirtualDevice::AquaSalVirtualDevice( AquaSalGraphics* pGraphic, long &nDX, long &nDY, + DeviceFormat eFormat, const SystemGraphicsData *pData ) + : mbGraphicsUsed( false ) + , mnBitmapDepth( 0 ) + , mnWidth(0) + , mnHeight(0) +{ + SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::AquaSalVirtualDevice() this=" << this + << " size=(" << nDX << "x" << nDY << ") bitcount=" << static_cast(eFormat) << + " pData=" << pData << " context=" << (pData ? pData->rCGContext : nullptr) ); + + 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. + // the mxContext is from pData (what "mxContext"? there is no such field anywhere in vcl;) + mbForeignContext = true; + mpGraphics = new AquaSalGraphics( /*pGraphic*/ ); + if (nDX == 0) + { + nDX = 1; + } + if (nDY == 0) + { + nDY = 1; + } + maLayer.set(CGLayerCreateWithContext(pData->rCGContext, CGSizeMake(nDX, nDY), nullptr)); + // Interrogate the context as to its real size + if (maLayer.isSet()) + { + const CGSize aSize = CGLayerGetSize(maLayer.get()); + nDX = static_cast(aSize.width); + nDY = static_cast(aSize.height); + } + else + { + nDX = 0; + nDY = 0; + } + + mpGraphics->SetVirDevGraphics(maLayer, pData->rCGContext); + } + else + { + // create empty new virtual device + mbForeignContext = false; // the mxContext is created within VCL + mpGraphics = new AquaSalGraphics(); // never fails + switch (eFormat) + { + case DeviceFormat::BITMASK: + mnBitmapDepth = 1; + break; +#ifdef IOS + case DeviceFormat::GRAYSCALE: + mnBitmapDepth = 8; + break; +#endif + default: + mnBitmapDepth = 0; + break; + } +#ifdef MACOSX + // inherit resolution from reference device + if( pGraphic ) + { + AquaSalFrame* pFrame = pGraphic->getGraphicsFrame(); + if( pFrame && AquaSalFrame::isAlive( pFrame ) ) + { + mpGraphics->setGraphicsFrame( pFrame ); + mpGraphics->copyResolution( *pGraphic ); + } + } +#endif + if( nDX && nDY ) + { + SetSize( nDX, nDY ); + } + // NOTE: if SetSize does not succeed, we just ignore the nDX and nDY + } +} + +AquaSalVirtualDevice::~AquaSalVirtualDevice() +{ + SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::~AquaSalVirtualDevice() this=" << this ); + + if( mpGraphics ) + { + mpGraphics->SetVirDevGraphics( nullptr, nullptr ); + delete mpGraphics; + mpGraphics = nullptr; + } + Destroy(); +} + +void AquaSalVirtualDevice::Destroy() +{ + SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::Destroy() this=" << this << " mbForeignContext=" << mbForeignContext ); + + if( mbForeignContext ) + { + // Do not delete mxContext that we have received from outside VCL + maLayer.set(nullptr); + return; + } + + if (maLayer.isSet()) + { + if( mpGraphics ) + { + mpGraphics->SetVirDevGraphics(nullptr, nullptr); + } + CGLayerRelease(maLayer.get()); + maLayer.set(nullptr); + } + + if (maBitmapContext.isSet()) + { + void* pRawData = CGBitmapContextGetData(maBitmapContext.get()); + std::free(pRawData); + CGContextRelease(maBitmapContext.get()); + maBitmapContext.set(nullptr); + } +} + +SalGraphics* AquaSalVirtualDevice::AcquireGraphics() +{ + if( mbGraphicsUsed || !mpGraphics ) + { + return nullptr; + } + mbGraphicsUsed = true; + return mpGraphics; +} + +void AquaSalVirtualDevice::ReleaseGraphics( SalGraphics* ) +{ + mbGraphicsUsed = false; +} + +bool AquaSalVirtualDevice::SetSize( long nDX, long nDY ) +{ + SAL_INFO( "vcl.virdev", "AquaSalVirtualDevice::SetSize() this=" << this << + " (" << nDX << "x" << nDY << ") mbForeignContext=" << (mbForeignContext ? "YES" : "NO")); + + if( mbForeignContext ) + { + // Do not delete/resize mxContext that we have received from outside VCL + return true; + } + + if (maLayer.isSet()) + { + const CGSize aSize = CGLayerGetSize(maLayer.get()); + if( (nDX == aSize.width) && (nDY == aSize.height) ) + { + // Yay, we do not have to do anything :) + return true; + } + } + + Destroy(); + + mnWidth = nDX; + mnHeight = nDY; + + // create a Quartz layer matching to the intended virdev usage + CGContextHolder xCGContextHolder; + if( mnBitmapDepth && (mnBitmapDepth < 16) ) + { + mnBitmapDepth = 8; // TODO: are 1bit vdevs worth it? + const int nBytesPerRow = (mnBitmapDepth * nDX + 7) / 8; + + void* pRawData = std::malloc( nBytesPerRow * nDY ); + maBitmapContext.set(CGBitmapContextCreate( pRawData, nDX, nDY, + mnBitmapDepth, nBytesPerRow, + GetSalData()->mxGraySpace, kCGImageAlphaNone)); + xCGContextHolder = maBitmapContext; + } + else + { +#ifdef MACOSX + // default to a NSView target context + AquaSalFrame* pSalFrame = mpGraphics->getGraphicsFrame(); + if( !pSalFrame || !AquaSalFrame::isAlive( pSalFrame )) + { + pSalFrame = static_cast( GetSalData()->mpInstance->anyFrame() ); + if ( pSalFrame ) + // update the frame reference + mpGraphics->setGraphicsFrame( pSalFrame ); + } + if( pSalFrame ) + { + // #i91990# + NSWindow* pNSWindow = pSalFrame->getNSWindow(); + if ( pNSWindow ) + { + NSGraphicsContext* pNSContext = [NSGraphicsContext graphicsContextWithWindow: pNSWindow]; + if( pNSContext ) + { + xCGContextHolder.set([pNSContext CGContext]); + } + } + } +#endif + + if (!xCGContextHolder.isSet()) + { + // assert(Application::IsBitmapRendering()); + mnBitmapDepth = 32; + + const int nBytesPerRow = (mnBitmapDepth * nDX) / 8; + void* pRawData = std::malloc( nBytesPerRow * nDY ); +#ifdef MACOSX + const int nFlags = kCGImageAlphaNoneSkipFirst; +#else + const int nFlags = kCGImageAlphaNoneSkipFirst | kCGImageByteOrder32Little; +#endif + maBitmapContext.set(CGBitmapContextCreate(pRawData, nDX, nDY, 8, nBytesPerRow, + GetSalData()->mxRGBSpace, nFlags)); + xCGContextHolder = maBitmapContext; + } + } + + SAL_WARN_IF(!xCGContextHolder.isSet(), "vcl.quartz", "No context"); + + const CGSize aNewSize = { static_cast(nDX), static_cast(nDY) }; + maLayer.set(CGLayerCreateWithContext(xCGContextHolder.get(), aNewSize, nullptr)); + + if (maLayer.isSet() && mpGraphics) + { + // get the matching Quartz context + CGContextRef xDrawContext = CGLayerGetContext( maLayer.get() ); + mpGraphics->SetVirDevGraphics(maLayer.get(), xDrawContext, mnBitmapDepth); + } + + return maLayer.isSet(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/utils.cxx b/vcl/quartz/utils.cxx new file mode 100644 index 000000000..0e0ac8f4d --- /dev/null +++ b/vcl/quartz/utils.cxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include +#include + +#include + +OUString GetOUString( CFStringRef rStr ) +{ + if( rStr == nullptr ) + { + return OUString(); + } + + CFIndex nLength = CFStringGetLength( rStr ); + if( nLength == 0 ) + { + return OUString(); + } + + const UniChar* pConstStr = CFStringGetCharactersPtr( rStr ); + if( pConstStr ) + { + return OUString( reinterpret_cast(pConstStr), nLength ); + } + + std::unique_ptr pStr(new UniChar[nLength]); + CFRange aRange = { 0, nLength }; + CFStringGetCharacters( rStr, aRange, pStr.get() ); + + OUString aRet( reinterpret_cast(pStr.get()), nLength ); + return aRet; +} + +OUString GetOUString( const NSString* pStr ) +{ + if( ! pStr ) + { + return OUString(); + } + + int nLen = [pStr length]; + if( nLen == 0 ) + { + return OUString(); + } + + OUStringBuffer aBuf( nLen+1 ); + aBuf.setLength( nLen ); + [pStr getCharacters: + reinterpret_cast(const_cast(aBuf.getStr()))]; + + return aBuf.makeStringAndClear(); +} + +CFStringRef CreateCFString( const OUString& rStr ) +{ + return CFStringCreateWithCharacters(kCFAllocatorDefault, reinterpret_cast(rStr.getStr()), rStr.getLength() ); +} + +NSString* CreateNSString( const OUString& rStr ) +{ + return [[NSString alloc] initWithCharacters: reinterpret_cast(rStr.getStr()) length: rStr.getLength()]; +} + +std::ostream &operator <<(std::ostream& s, const CGRect &rRect) +{ +#ifndef SAL_LOG_INFO + (void) rRect; +#else + if (CGRectIsNull(rRect)) + { + s << "NULL"; + } + else + { + s << rRect.size << "@" << rRect.origin; + } +#endif + return s; +} + +std::ostream &operator <<(std::ostream& s, const CGPoint &rPoint) +{ +#ifndef SAL_LOG_INFO + (void) rPoint; +#else + s << "(" << rPoint.x << "," << rPoint.y << ")"; +#endif + return s; +} + +std::ostream &operator <<(std::ostream& s, const CGSize &rSize) +{ +#ifndef SAL_LOG_INFO + (void) rSize; +#else + s << rSize.width << "x" << rSize.height; +#endif + return s; +} + +std::ostream &operator <<(std::ostream& s, CGColorRef pColor) +{ +#ifndef SAL_LOG_INFO + (void) pColor; +#else + CFStringRef colorString = CFCopyDescription(pColor); + if (colorString) + { + s << GetOUString(colorString); + CFRelease(colorString); + } + else + { + s << "NULL"; + } +#endif + return s; +} + +std::ostream &operator <<(std::ostream& s, const CGAffineTransform &aXform) +{ +#ifndef SAL_LOG_INFO + (void) aXform; +#else + if (CGAffineTransformIsIdentity(aXform)) + { + s << "IDENT"; + } + else + { + s << "[" << aXform.a << "," << aXform.b << "," << aXform.c << "," << aXform.d << "," << aXform.tx << "," << aXform.ty << "]"; + } +#endif + return s; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/README b/vcl/skia/README new file mode 100644 index 000000000..f1248d90c --- /dev/null +++ b/vcl/skia/README @@ -0,0 +1,35 @@ +This is code for using the Skia library as a drawing library in VCL backends. +See external/skia for info on the library itself. + +Environment variables: +====================== + +See README.vars in the toplevel vcl/ directory. Note that many backends do not +use Skia. E.g. on Linux it is necessary to also use SAL_USE_VCLPLUGIN=gen . + +There are also GUI options for controlling whether Skia is enabled. + +Skia drawing methods: +===================== + +Skia supports several methods to draw: +- Raster - CPU-based drawing (here primarily used for debugging) +- Vulkan - Vulkan-based GPU drawing, this is the default + +There are more (OpenGL, Metal on Mac, etc.), but (as of now) they are not supported by VCL. + +GrContext sharing: +================== + +We use Skia's sk_app::WindowContext class for creating surfaces for windows, that class +takes care of the internals. But of offscreen drawing, we need an instance of class +GrContext. There is sk_app::WindowContext::getGrContext(), but each instance creates +its own GrContext, and apparently it does not work to mix them. Which means that +for offscreen drawing we would need to know which window (and only that window) +the contents will be eventually painted to, which is not possible (it may not even +be known at the time). + +To solve this problem we patch sk_app::WindowContext to create just one GrContext object +and share it between instances. Additionally, using sk_app::WindowContext::SharedGrContext +it is possible to share it also for offscreen drawing, including keeping proper reference +count. diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx new file mode 100644 index 000000000..343ebc284 --- /dev/null +++ b/vcl/skia/SkiaHelper.cxx @@ -0,0 +1,611 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#if !HAVE_FEATURE_SKIA + +namespace SkiaHelper +{ +bool isVCLSkiaEnabled() { return false; } + +} // namespace + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef DBG_UTIL +#include +#endif + +namespace SkiaHelper +{ +static OUString getBlacklistFile() +{ + OUString url("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER); + rtl::Bootstrap::expandMacros(url); + + return url + "/skia/skia_blacklist_vulkan.xml"; +} + +static uint32_t driverVersion = 0; +uint32_t vendorId = 0; + +static OUString versionAsString(uint32_t version) +{ + return OUString::number(version >> 22) + "." + OUString::number((version >> 12) & 0x3ff) + "." + + OUString::number(version & 0xfff); +} + +static OUStringLiteral vendorAsString(uint32_t vendor) +{ + return DriverBlocklist::GetVendorNameFromId(vendor); +} + +static OUString getCacheFolder() +{ + OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER + "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/"); + rtl::Bootstrap::expandMacros(url); + osl::Directory::create(url); + return url; +} + +static void writeToLog(SvStream& stream, const char* key, const char* value) +{ + stream.WriteCharPtr(key); + stream.WriteCharPtr(": "); + stream.WriteCharPtr(value); + stream.WriteChar('\n'); +} + +static void writeToLog(SvStream& stream, const char* key, const OUString& value) +{ + writeToLog(stream, key, OUStringToOString(value, RTL_TEXTENCODING_UTF8).getStr()); +} + +// Note that this function also logs system information about Vulkan. +static bool isVulkanBlacklisted(const VkPhysicalDeviceProperties& props) +{ + static const char* const types[] + = { "other", "integrated", "discrete", "virtual", "cpu", "??" }; // VkPhysicalDeviceType + driverVersion = props.driverVersion; + vendorId = props.vendorID; + OUString vendorIdStr = "0x" + OUString::number(props.vendorID, 16); + OUString deviceIdStr = "0x" + OUString::number(props.deviceID, 16); + OUString driverVersionString = versionAsString(driverVersion); + OUString apiVersion = versionAsString(props.apiVersion); + const char* deviceType = types[std::min(props.deviceType, SAL_N_ELEMENTS(types) - 1)]; + + CrashReporter::addKeyValue("VulkanVendor", vendorIdStr, CrashReporter::AddItem); + CrashReporter::addKeyValue("VulkanDevice", deviceIdStr, CrashReporter::AddItem); + CrashReporter::addKeyValue("VulkanAPI", apiVersion, CrashReporter::AddItem); + CrashReporter::addKeyValue("VulkanDriver", driverVersionString, CrashReporter::AddItem); + CrashReporter::addKeyValue("VulkanDeviceType", OUString::createFromAscii(deviceType), + CrashReporter::AddItem); + CrashReporter::addKeyValue("VulkanDeviceName", OUString::createFromAscii(props.deviceName), + CrashReporter::Write); + + SvFileStream logFile(getCacheFolder() + "/skia.log", StreamMode::WRITE | StreamMode::TRUNC); + writeToLog(logFile, "RenderMethod", "vulkan"); + writeToLog(logFile, "Vendor", vendorIdStr); + writeToLog(logFile, "Device", deviceIdStr); + writeToLog(logFile, "API", apiVersion); + writeToLog(logFile, "Driver", driverVersionString); + writeToLog(logFile, "DeviceType", deviceType); + writeToLog(logFile, "DeviceName", props.deviceName); + + SAL_INFO("vcl.skia", + "Vulkan API version: " << apiVersion << ", driver version: " << driverVersionString + << ", vendor: " << vendorIdStr << " (" + << vendorAsString(vendorId) << "), device: " << deviceIdStr + << ", type: " << deviceType << ", name: " << props.deviceName); + bool blacklisted + = DriverBlocklist::IsDeviceBlocked(getBlacklistFile(), DriverBlocklist::VersionType::Vulkan, + driverVersionString, vendorIdStr, deviceIdStr); + writeToLog(logFile, "Blacklisted", blacklisted ? "yes" : "no"); + return blacklisted; +} + +static void writeSkiaRasterInfo() +{ + SvFileStream logFile(getCacheFolder() + "/skia.log", StreamMode::WRITE | StreamMode::TRUNC); + writeToLog(logFile, "RenderMethod", "raster"); + // Log compiler, Skia works best when compiled with Clang. + writeToLog(logFile, "Compiler", skia_compiler_name()); +} + +static sk_app::VulkanWindowContext::SharedGrContext getTemporaryGrContext(); + +static void checkDeviceBlacklisted(bool blockDisable = false) +{ + static bool done = false; + if (!done) + { + SkiaZone zone; + + switch (renderMethodToUse()) + { + case RenderVulkan: + { + // First try if a GrContext already exists. + sk_app::VulkanWindowContext::SharedGrContext grContext + = sk_app::VulkanWindowContext::getSharedGrContext(); + if (!grContext.getGrContext()) + { + // This function is called from isVclSkiaEnabled(), which + // may be called when deciding which X11 visual to use, + // and that visual is normally needed when creating + // Skia's VulkanWindowContext, which is needed for the GrContext. + // Avoid the loop by creating a temporary GrContext + // that will use the default X11 visual (that shouldn't matter + // for just finding out information about Vulkan) and destroying + // the temporary context will clean up again. + grContext = getTemporaryGrContext(); + } + bool blacklisted = true; // assume the worst + if (grContext.getGrContext()) // Vulkan was initialized properly + { + blacklisted = isVulkanBlacklisted( + sk_app::VulkanWindowContext::getPhysDeviceProperties()); + SAL_INFO("vcl.skia", "Vulkan blacklisted: " << blacklisted); + } + else + SAL_INFO("vcl.skia", "Vulkan could not be initialized"); + if (blacklisted && !blockDisable) + { + disableRenderMethod(RenderVulkan); + writeSkiaRasterInfo(); + } + break; + } + case RenderRaster: + SAL_INFO("vcl.skia", "Using Skia raster mode"); + writeSkiaRasterInfo(); + return; // software, never blacklisted + } + done = true; + } +} + +static bool skiaSupportedByBackend = false; +static bool supportsVCLSkia() +{ + if (!skiaSupportedByBackend) + { + SAL_INFO("vcl.skia", "Skia not supported by VCL backend, disabling"); + return false; + } + return getenv("SAL_DISABLESKIA") == nullptr; +} + +bool isVCLSkiaEnabled() +{ + /** + * The !bSet part should only be called once! Changing the results in the same + * run will mix Skia and normal rendering. + */ + + static bool bSet = false; + static bool bEnable = false; + static bool bForceSkia = false; + + // No hardware rendering, so no Skia + // TODO SKIA + if (Application::IsBitmapRendering()) + return false; + + if (bSet) + { + return bForceSkia || bEnable; + } + + /* + * There are a number of cases that these environment variables cover: + * * SAL_FORCESKIA forces Skia if disabled by UI options or blacklisted + * * SAL_DISABLESKIA avoids the use of Skia regardless of any option + */ + + bSet = true; + bForceSkia = !!getenv("SAL_FORCESKIA") || officecfg::Office::Common::VCL::ForceSkia::get(); + + bool bRet = false; + bool bSupportsVCLSkia = supportsVCLSkia(); + if (bForceSkia && bSupportsVCLSkia) + { + bRet = true; + SkGraphics::Init(); + // don't actually block if blacklisted, but log it if enabled, and also get the vendor id + checkDeviceBlacklisted(true); + } + else if (getenv("SAL_FORCEGL")) + { + // Skia usage is checked before GL usage, so if GL is forced (and Skia is not), do not + // enable Skia in order to allow GL. + bRet = false; + } + else if (bSupportsVCLSkia) + { + static bool bEnableSkiaEnv = !!getenv("SAL_ENABLESKIA"); + + bEnable = bEnableSkiaEnv; + + if (officecfg::Office::Common::VCL::UseSkia::get()) + bEnable = true; + + // Force disable in safe mode + if (Application::IsSafeModeEnabled()) + bEnable = false; + + if (bEnable) + { + SkGraphics::Init(); + checkDeviceBlacklisted(); // switch to raster if driver is blacklisted + } + + bRet = bEnable; + } + + if (bRet) + WatchdogThread::start(); + + CrashReporter::addKeyValue("UseSkia", OUString::boolean(bRet), CrashReporter::Write); + + return bRet; +} + +static RenderMethod methodToUse = RenderRaster; + +static bool initRenderMethodToUse() +{ + if (const char* env = getenv("SAL_SKIA")) + { + if (strcmp(env, "raster") == 0) + { + methodToUse = RenderRaster; + return true; + } + if (strcmp(env, "vulkan") == 0) + { + methodToUse = RenderVulkan; + return true; + } + SAL_WARN("vcl.skia", "Unrecognized value of SAL_SKIA"); + abort(); + } + if (officecfg::Office::Common::VCL::ForceSkiaRaster::get()) + { + methodToUse = RenderRaster; + return true; + } + methodToUse = RenderVulkan; + return true; +} + +RenderMethod renderMethodToUse() +{ + static bool methodToUseInited = initRenderMethodToUse(); + if (methodToUseInited) // Used just to ensure thread-safe one-time init. + return methodToUse; + abort(); +} + +void disableRenderMethod(RenderMethod method) +{ + if (renderMethodToUse() != method) + return; + // Choose a fallback, right now always raster. + methodToUse = RenderRaster; +} + +static sk_app::VulkanWindowContext::SharedGrContext* sharedGrContext; + +static std::unique_ptr (*createVulkanWindowContextFunction)(bool) = nullptr; +static void setCreateVulkanWindowContext(std::unique_ptr (*function)(bool)) +{ + createVulkanWindowContextFunction = function; +} + +GrContext* getSharedGrContext() +{ + SkiaZone zone; + assert(renderMethodToUse() == RenderVulkan); + if (sharedGrContext) + return sharedGrContext->getGrContext(); + // TODO mutex? + // Set up the shared GrContext from Skia's (patched) VulkanWindowContext, if it's been + // already set up. + sk_app::VulkanWindowContext::SharedGrContext context + = sk_app::VulkanWindowContext::getSharedGrContext(); + GrContext* grContext = context.getGrContext(); + if (grContext) + { + sharedGrContext = new sk_app::VulkanWindowContext::SharedGrContext(context); + return grContext; + } + static bool done = false; + if (done) + return nullptr; + done = true; + if (createVulkanWindowContextFunction == nullptr) + return nullptr; // not initialized properly (e.g. used from a VCL backend with no Skia support) + std::unique_ptr tmpContext = createVulkanWindowContextFunction(false); + // Set up using the shared context created by the call above, if successful. + context = sk_app::VulkanWindowContext::getSharedGrContext(); + grContext = context.getGrContext(); + if (grContext) + { + sharedGrContext = new sk_app::VulkanWindowContext::SharedGrContext(context); + return grContext; + } + disableRenderMethod(RenderVulkan); + return nullptr; +} + +static sk_app::VulkanWindowContext::SharedGrContext getTemporaryGrContext() +{ + if (createVulkanWindowContextFunction == nullptr) + return sk_app::VulkanWindowContext::SharedGrContext(); + std::unique_ptr tmpContext = createVulkanWindowContextFunction(true); + // Set up using the shared context created by the call above, if successful. + return sk_app::VulkanWindowContext::getSharedGrContext(); +} + +sk_sp createSkSurface(int width, int height, SkColorType type) +{ + SkiaZone zone; + assert(type == kN32_SkColorType || type == kAlpha_8_SkColorType); + sk_sp surface; + switch (SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderVulkan: + { + if (GrContext* grContext = getSharedGrContext()) + { + surface = SkSurface::MakeRenderTarget( + grContext, SkBudgeted::kNo, + SkImageInfo::Make(width, height, type, kPremul_SkAlphaType)); + if (surface) + { +#ifdef DBG_UTIL + prefillSurface(surface); +#endif + return surface; + } + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU offscreen surface, falling back to Raster"); + } + break; + } + default: + break; + } + // Create raster surface as a fallback. + surface = SkSurface::MakeRaster(SkImageInfo::Make(width, height, type, kPremul_SkAlphaType)); + assert(surface); + if (surface) + { +#ifdef DBG_UTIL + prefillSurface(surface); +#endif + return surface; + } + // In non-debug builds we could return SkSurface::MakeNull() and try to cope with the situation, + // but that can lead to unnoticed data loss, so better fail clearly. + abort(); +} + +sk_sp createSkImage(const SkBitmap& bitmap) +{ + SkiaZone zone; + assert(bitmap.colorType() == kN32_SkColorType || bitmap.colorType() == kAlpha_8_SkColorType); + switch (SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderVulkan: + { + if (GrContext* grContext = getSharedGrContext()) + { + sk_sp surface = SkSurface::MakeRenderTarget( + grContext, SkBudgeted::kNo, bitmap.info().makeAlphaType(kPremul_SkAlphaType)); + if (surface) + { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + surface->getCanvas()->drawBitmap(bitmap, 0, 0, &paint); + return makeCheckedImageSnapshot(surface); + } + // Try to fall back in non-debug builds. + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU offscreen surface, falling back to Raster"); + } + break; + } + default: + break; + } + // Create raster image as a fallback. + sk_sp image = SkImage::MakeFromBitmap(bitmap); + assert(image); + return image; +} + +sk_sp makeCheckedImageSnapshot(sk_sp surface) +{ + sk_sp ret = surface->makeImageSnapshot(); + assert(ret); + if (ret) + return ret; + abort(); +} + +sk_sp makeCheckedImageSnapshot(sk_sp surface, const SkIRect& bounds) +{ + sk_sp ret = surface->makeImageSnapshot(bounds); + assert(ret); + if (ret) + return ret; + abort(); +} + +namespace +{ +// Image cache, for saving results of complex operations such as drawTransformedBitmap(). +struct ImageCacheItem +{ + OString key; + sk_sp image; + int size; // cost of the item +}; +} //namespace + +// LRU cache, last item is the least recently used. Hopefully there won't be that many items +// to require a hash/map. Using o3tl::lru_cache would be simpler, but it doesn't support +// calculating cost of each item. +static std::list* imageCache = nullptr; +static int imageCacheSize = 0; // sum of all ImageCacheItem.size + +void addCachedImage(const OString& key, sk_sp image) +{ + static bool disabled = getenv("SAL_DISABLE_SKIA_CACHE") != nullptr; + if (disabled) + return; + if (imageCache == nullptr) + imageCache = new std::list; + int size = image->width() * image->height() + * SkColorTypeBytesPerPixel(image->imageInfo().colorType()); + imageCache->push_front({ key, image, size }); + imageCacheSize += size; + SAL_INFO("vcl.skia.trace", "addcachedimage " << image << " :" << size << "/" << imageCacheSize); + const int MAX_CACHE_SIZE = 4 * 1000 * 1000 * 4; // 4x 1000px 32bpp images, 16MiB + while (imageCacheSize > MAX_CACHE_SIZE) + { + assert(!imageCache->empty()); + imageCacheSize -= imageCache->back().size; + SAL_INFO("vcl.skia.trace", + "least used removal " << image << ":" << imageCache->back().size); + imageCache->pop_back(); + } +} + +sk_sp findCachedImage(const OString& key) +{ + if (imageCache != nullptr) + { + for (auto it = imageCache->begin(); it != imageCache->end(); ++it) + { + if (it->key == key) + { + sk_sp ret = it->image; + SAL_INFO("vcl.skia.trace", + "findcachedimage " << key << " : " << it->image << " found"); + imageCache->splice(imageCache->begin(), *imageCache, it); + return ret; + } + } + } + SAL_INFO("vcl.skia.trace", "findcachedimage " << key << " not found"); + return nullptr; +} + +void removeCachedImage(sk_sp image) +{ + if (imageCache == nullptr) + return; + for (auto it = imageCache->begin(); it != imageCache->end();) + { + if (it->image == image) + { + imageCacheSize -= it->size; + assert(imageCacheSize >= 0); + it = imageCache->erase(it); + } + else + ++it; + } +} + +void cleanup() +{ + delete sharedGrContext; + sharedGrContext = nullptr; + delete imageCache; + imageCache = nullptr; + imageCacheSize = 0; +} + +// Skia should not be used from VCL backends that do not actually support it, as there will be setup missing. +// The code here (that is in the vcl lib) needs a function for creating Vulkan context that is +// usually available only in the backend libs. +void prepareSkia(std::unique_ptr (*createVulkanWindowContext)(bool)) +{ + setCreateVulkanWindowContext(createVulkanWindowContext); + skiaSupportedByBackend = true; +} + +#ifdef DBG_UTIL +void prefillSurface(sk_sp& surface) +{ + // Pre-fill the surface with deterministic garbage. + SkBitmap bitmap; + bitmap.allocN32Pixels(2, 2); + SkPMColor* scanline; + scanline = bitmap.getAddr32(0, 0); + *scanline++ = SkPreMultiplyARGB(0xFF, 0xBF, 0x80, 0x40); + *scanline++ = SkPreMultiplyARGB(0xFF, 0x40, 0x80, 0xBF); + scanline = bitmap.getAddr32(0, 1); + *scanline++ = SkPreMultiplyARGB(0xFF, 0xE3, 0x5C, 0x13); + *scanline++ = SkPreMultiplyARGB(0xFF, 0x13, 0x5C, 0xE3); + bitmap.setImmutable(); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + paint.setShader(bitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat)); + surface->getCanvas()->drawPaint(paint); +} + +void dump(const SkBitmap& bitmap, const char* file) { dump(SkImage::MakeFromBitmap(bitmap), file); } + +void dump(const sk_sp& surface, const char* file) +{ + surface->getCanvas()->flush(); + dump(makeCheckedImageSnapshot(surface), file); +} + +void dump(const sk_sp& image, const char* file) +{ + sk_sp data = image->encodeToData(); + std::ofstream ostream(file, std::ios::binary); + ostream.write(static_cast(data->data()), data->size()); +} + +#endif + +} // namespace + +#endif // HAVE_FEATURE_SKIA + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx new file mode 100644 index 000000000..bd497d7f8 --- /dev/null +++ b/vcl/skia/gdiimpl.cxx @@ -0,0 +1,1829 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace +{ +// Create Skia Path from B2DPolygon +// Note that polygons generally have the complication that when used +// for area (fill) operations they usually miss the right-most and +// bottom-most line of pixels of the bounding rectangle (see +// https://lists.freedesktop.org/archives/libreoffice/2019-November/083709.html). +// So be careful with rectangle->polygon conversions (generally avoid them). +void addPolygonToPath(const basegfx::B2DPolygon& rPolygon, SkPath& rPath, + bool* hasOnlyOrthogonal = nullptr) +{ + const sal_uInt32 nPointCount(rPolygon.count()); + + if (nPointCount <= 1) + return; + + const bool bClosePath(rPolygon.isClosed()); + const bool bHasCurves(rPolygon.areControlPointsUsed()); + + bool bFirst = true; + + sal_uInt32 nCurrentIndex = 0; + sal_uInt32 nPreviousIndex = nPointCount - 1; + + basegfx::B2DPoint aCurrentPoint; + basegfx::B2DPoint aPreviousPoint; + + for (sal_uInt32 nIndex = 0; nIndex <= nPointCount; nIndex++) + { + if (nIndex == nPointCount && !bClosePath) + continue; + + // Make sure we loop the last point to first point + nCurrentIndex = nIndex % nPointCount; + aCurrentPoint = rPolygon.getB2DPoint(nCurrentIndex); + + if (bFirst) + { + rPath.moveTo(aCurrentPoint.getX(), aCurrentPoint.getY()); + bFirst = false; + } + else if (!bHasCurves) + { + rPath.lineTo(aCurrentPoint.getX(), aCurrentPoint.getY()); + // If asked for, check whether the polygon has a line that is not + // strictly horizontal or vertical. + if (hasOnlyOrthogonal != nullptr && aCurrentPoint.getX() != aPreviousPoint.getX() + && aCurrentPoint.getY() != aPreviousPoint.getY()) + *hasOnlyOrthogonal = false; + } + else + { + basegfx::B2DPoint aPreviousControlPoint = rPolygon.getNextControlPoint(nPreviousIndex); + basegfx::B2DPoint aCurrentControlPoint = rPolygon.getPrevControlPoint(nCurrentIndex); + + if (aPreviousControlPoint.equal(aPreviousPoint)) + { + aPreviousControlPoint + = aPreviousPoint + ((aPreviousControlPoint - aCurrentPoint) * 0.0005); + } + + if (aCurrentControlPoint.equal(aCurrentPoint)) + { + aCurrentControlPoint + = aCurrentPoint + ((aCurrentControlPoint - aPreviousPoint) * 0.0005); + } + rPath.cubicTo(aPreviousControlPoint.getX(), aPreviousControlPoint.getY(), + aCurrentControlPoint.getX(), aCurrentControlPoint.getY(), + aCurrentPoint.getX(), aCurrentPoint.getY()); + if (hasOnlyOrthogonal != nullptr) + *hasOnlyOrthogonal = false; + } + aPreviousPoint = aCurrentPoint; + nPreviousIndex = nCurrentIndex; + } + if (bClosePath) + { + rPath.close(); + } +} + +void addPolyPolygonToPath(const basegfx::B2DPolyPolygon& rPolyPolygon, SkPath& rPath, + bool* hasOnlyOrthogonal = nullptr) +{ + const sal_uInt32 nPolygonCount(rPolyPolygon.count()); + + if (nPolygonCount == 0) + return; + + for (const auto& rPolygon : rPolyPolygon) + { + addPolygonToPath(rPolygon, rPath, hasOnlyOrthogonal); + } +} + +// Check if the given polygon contains a straight line. If not, it consists +// solely of curves. +bool polygonContainsLine(const basegfx::B2DPolyPolygon& rPolyPolygon) +{ + if (!rPolyPolygon.areControlPointsUsed()) + return true; // no curves at all + for (const auto& rPolygon : rPolyPolygon) + { + const sal_uInt32 nPointCount(rPolygon.count()); + bool bFirst = true; + + const bool bClosePath(rPolygon.isClosed()); + + sal_uInt32 nCurrentIndex = 0; + sal_uInt32 nPreviousIndex = nPointCount - 1; + + basegfx::B2DPoint aCurrentPoint; + basegfx::B2DPoint aPreviousPoint; + + for (sal_uInt32 nIndex = 0; nIndex <= nPointCount; nIndex++) + { + if (nIndex == nPointCount && !bClosePath) + continue; + + // Make sure we loop the last point to first point + nCurrentIndex = nIndex % nPointCount; + if (bFirst) + bFirst = false; + else + { + basegfx::B2DPoint aPreviousControlPoint + = rPolygon.getNextControlPoint(nPreviousIndex); + basegfx::B2DPoint aCurrentControlPoint + = rPolygon.getPrevControlPoint(nCurrentIndex); + + if (aPreviousControlPoint.equal(aPreviousPoint) + && aCurrentControlPoint.equal(aCurrentPoint)) + { + return true; // found a straight line + } + } + aPreviousPoint = aCurrentPoint; + nPreviousIndex = nCurrentIndex; + } + } + return false; // no straight line found +} + +SkColor toSkColor(Color color) +{ + return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed(), color.GetGreen(), + color.GetBlue()); +} + +SkColor toSkColorWithTransparency(Color aColor, double fTransparency) +{ + return SkColorSetA(toSkColor(aColor), 255 * (1.0 - fTransparency)); +} + +Color fromSkColor(SkColor color) +{ + return Color(255 - SkColorGetA(color), SkColorGetR(color), SkColorGetG(color), + SkColorGetB(color)); +} + +// returns true if the source or destination rectangles are invalid +bool checkInvalidSourceOrDestination(SalTwoRect const& rPosAry) +{ + return rPosAry.mnSrcWidth <= 0 || rPosAry.mnSrcHeight <= 0 || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0; +} + +} // end anonymous namespace + +// Class that triggers flushing the backing buffer when idle. +class SkiaFlushIdle : public Idle +{ + SkiaSalGraphicsImpl* mpGraphics; +#ifndef NDEBUG + char* debugname; +#endif + +public: + explicit SkiaFlushIdle(SkiaSalGraphicsImpl* pGraphics) + : Idle(get_debug_name(pGraphics)) + , mpGraphics(pGraphics) + { + // We don't want to be swapping before we've painted. + SetPriority(TaskPriority::POST_PAINT); + } +#ifndef NDEBUG + virtual ~SkiaFlushIdle() { free(debugname); } + const char* get_debug_name(SkiaSalGraphicsImpl* pGraphics) + { + // Idle keeps just a pointer, so we need to store the string + debugname = strdup( + OString("skia idle 0x" + OString::number(reinterpret_cast(pGraphics), 16)) + .getStr()); + return debugname; + } +#else + const char* get_debug_name(SkiaSalGraphicsImpl*) { return "skia idle"; } +#endif + + virtual void Invoke() override + { + mpGraphics->performFlush(); + Stop(); + SetPriority(TaskPriority::HIGHEST); + } +}; + +SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider* pProvider) + : mParent(rParent) + , mProvider(pProvider) + , mIsGPU(false) + , mLineColor(SALCOLOR_NONE) + , mFillColor(SALCOLOR_NONE) + , mXorMode(false) + , mFlush(new SkiaFlushIdle(this)) +{ +} + +SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl() +{ + assert(!mSurface); + assert(!mWindowContext); +} + +void SkiaSalGraphicsImpl::Init() {} + +void SkiaSalGraphicsImpl::createSurface() +{ + SkiaZone zone; + if (isOffscreen()) + createOffscreenSurface(); + else + createWindowSurface(); + mSurface->getCanvas()->save(); // see SetClipRegion() + mClipRegion = vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight())); + + // We don't want to be swapping before we've painted. + mFlush->Stop(); + mFlush->SetPriority(TaskPriority::POST_PAINT); +} + +void SkiaSalGraphicsImpl::createWindowSurface(bool forceRaster) +{ + SkiaZone zone; + assert(!isOffscreen()); + assert(!mSurface); + assert(!mWindowContext); + createWindowContext(forceRaster); + if (mWindowContext) + mSurface = mWindowContext->getBackbufferSurface(); + if (!mSurface) + { + switch (SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderVulkan: + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU window surface, falling back to Raster"); + destroySurface(); // destroys also WindowContext + return createWindowSurface(true); // try again + case SkiaHelper::RenderRaster: + abort(); // This should not really happen, do not even try to cope with it. + } + } + mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; +#ifdef DBG_UTIL + SkiaHelper::prefillSurface(mSurface); +#endif +} + +void SkiaSalGraphicsImpl::createOffscreenSurface() +{ + SkiaZone zone; + assert(isOffscreen()); + assert(!mSurface); + assert(!mWindowContext); + // When created (especially on Windows), Init() gets called with size (0,0), which is invalid size + // for Skia. May happen also in rare cases such as shutting down (tdf#131939). + int width = std::max(1, GetWidth()); + int height = std::max(1, GetHeight()); + switch (SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderVulkan: + { + if (SkiaHelper::getSharedGrContext()) + { + mSurface = SkiaHelper::createSkSurface(width, height); + if (mSurface) + { + mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; + return; + } + } + break; + } + default: + break; + } + // Create raster surface as a fallback. + mSurface = SkiaHelper::createSkSurface(width, height); + assert(mSurface); + assert(!mSurface->getCanvas()->getGrContext()); // is not GPU-backed + mIsGPU = false; +} + +void SkiaSalGraphicsImpl::destroySurface() +{ + SkiaZone zone; + if (mSurface) + { + // check setClipRegion() invariant + assert(mSurface->getCanvas()->getSaveCount() == 2); + // if this fails, something forgot to use SkAutoCanvasRestore + assert(mSurface->getCanvas()->getTotalMatrix().isIdentity()); + } + // If we use e.g. Vulkan, we must destroy the surface before the context, + // otherwise destroying the surface will reference the context. This is + // handled by calling destroySurface() before destroying the context. + // However we also need to flush the surface before destroying it, + // otherwise when destroying the context later there still could be queued + // commands referring to the surface data. This is probably a Skia bug, + // but work around it here. + if (mSurface) + mSurface->flushAndSubmit(); + mSurface.reset(); + mWindowContext.reset(); + mIsGPU = false; +} + +void SkiaSalGraphicsImpl::DeInit() { destroySurface(); } + +void SkiaSalGraphicsImpl::preDraw() +{ + assert(comphelper::SolarMutex::get()->IsCurrentThread()); + SkiaZone::enter(); // matched in postDraw() + checkSurface(); + checkPendingDrawing(); +} + +void SkiaSalGraphicsImpl::postDraw() +{ + scheduleFlush(); + SkiaZone::leave(); // matched in preDraw() + // If there's a problem with the GPU context, abort. + if (GrContext* context = mSurface->getCanvas()->getGrContext()) + { + // Running out of memory on the GPU technically could be possibly recoverable, + // but we don't know the exact status of the surface (and what has or has not been drawn to it), + // so in practice this is unrecoverable without possible data loss. + if (context->oomed()) + { + SAL_WARN("vcl.skia", "GPU context has run out of memory, aborting."); + abort(); + } + // Unrecoverable problem. + if (context->abandoned()) + { + SAL_WARN("vcl.skia", "GPU context has been abandoned, aborting."); + abort(); + } + } +} + +void SkiaSalGraphicsImpl::scheduleFlush() +{ + if (!isOffscreen()) + { + if (!Application::IsInExecute()) + performFlush(); // otherwise nothing would trigger idle rendering + else if (!mFlush->IsActive()) + mFlush->Start(); + } +} + +// VCL can sometimes resize us without telling us, update the surface if needed. +// Also create the surface on demand if it has not been created yet (it is a waste +// to create it in Init() if it gets recreated later anyway). +void SkiaSalGraphicsImpl::checkSurface() +{ + if (!mSurface) + { + createSurface(); + SAL_INFO("vcl.skia.trace", + "create(" << this << "): " << Size(mSurface->width(), mSurface->height())); + } + else if (GetWidth() != mSurface->width() || GetHeight() != mSurface->height()) + { + if (avoidRecreateByResize()) + return; + + if (!GetWidth() || !GetHeight()) + { + SAL_WARN("vcl.skia", "recreate(" << this << "): can't create empty surface " + << Size(GetWidth(), GetHeight()) + << " => keeping old one!"); + return; + } + + { + Size oldSize(mSurface->width(), mSurface->height()); + // Recreating a surface means that the old SkSurface contents will be lost. + // But if a window has been resized the windowing system may send repaint events + // only for changed parts and VCL would not repaint the whole area, assuming + // that some parts have not changed (this is what seems to cause tdf#131952). + // So carry over the old contents for windows, even though generally everything + // will be usually repainted anyway. + sk_sp snapshot; + if (!isOffscreen()) + { + flushDrawing(); + snapshot = SkiaHelper::makeCheckedImageSnapshot(mSurface); + } + + destroySurface(); + createSurface(); + + if (snapshot) + { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is + mSurface->getCanvas()->drawImage(snapshot, 0, 0, &paint); + } + SAL_INFO("vcl.skia.trace", "recreate(" << this << "): old " << oldSize << " new " + << Size(mSurface->width(), mSurface->height()) + << " requested " + << Size(GetWidth(), GetHeight())); + } + } +} + +void SkiaSalGraphicsImpl::flushDrawing() +{ + if (!mSurface) + return; + checkPendingDrawing(); + if (mXorMode) + applyXor(); + mSurface->flushAndSubmit(); +} + +bool SkiaSalGraphicsImpl::setClipRegion(const vcl::Region& region) +{ + if (mClipRegion == region) + return true; + SkiaZone zone; + checkPendingDrawing(); + checkSurface(); + mClipRegion = region; + SAL_INFO("vcl.skia.trace", "setclipregion(" << this << "): " << region); + SkCanvas* canvas = mSurface->getCanvas(); + // SkCanvas::clipRegion() can only further reduce the clip region, + // but we need to set the given region, which may extend it. + // So handle that by always having the full clip region saved on the stack + // and always go back to that. SkCanvas::restore() only affects the clip + // and the matrix. + assert(canvas->getSaveCount() == 2); // = there is just one save() + canvas->restore(); + canvas->save(); + setCanvasClipRegion(canvas, region); + return true; +} + +void SkiaSalGraphicsImpl::setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region) +{ + SkiaZone zone; + SkPath path; + // Always use region rectangles, regardless of what the region uses internally. + // That's what other VCL backends do, and trying to use addPolyPolygonToPath() + // in case a polygon is used leads to off-by-one errors such as tdf#133208. + RectangleVector rectangles; + region.GetRegionRectangles(rectangles); + for (const tools::Rectangle& rectangle : rectangles) + path.addRect(SkRect::MakeXYWH(rectangle.getX(), rectangle.getY(), rectangle.GetWidth(), + rectangle.GetHeight())); + path.setFillType(SkPathFillType::kEvenOdd); + canvas->clipPath(path); +} + +void SkiaSalGraphicsImpl::ResetClipRegion() +{ + setClipRegion(vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight()))); +} + +const vcl::Region& SkiaSalGraphicsImpl::getClipRegion() const { return mClipRegion; } + +sal_uInt16 SkiaSalGraphicsImpl::GetBitCount() const { return 32; } + +long SkiaSalGraphicsImpl::GetGraphicsWidth() const { return GetWidth(); } + +void SkiaSalGraphicsImpl::SetLineColor() +{ + checkPendingDrawing(); + mLineColor = SALCOLOR_NONE; +} + +void SkiaSalGraphicsImpl::SetLineColor(Color nColor) +{ + checkPendingDrawing(); + mLineColor = nColor; +} + +void SkiaSalGraphicsImpl::SetFillColor() +{ + checkPendingDrawing(); + mFillColor = SALCOLOR_NONE; +} + +void SkiaSalGraphicsImpl::SetFillColor(Color nColor) +{ + checkPendingDrawing(); + mFillColor = nColor; +} + +void SkiaSalGraphicsImpl::SetXORMode(bool set, bool) +{ + if (mXorMode == set) + return; + checkPendingDrawing(); + SAL_INFO("vcl.skia.trace", "setxormode(" << this << "): " << set); + if (set) + mXorRegion.setEmpty(); + else + applyXor(); + mXorMode = set; +} + +SkCanvas* SkiaSalGraphicsImpl::getXorCanvas() +{ + SkiaZone zone; + assert(mXorMode); + // Skia does not implement xor drawing, so we need to handle it manually by redirecting + // to a temporary SkBitmap and then doing the xor operation on the data ourselves. + // There's no point in using SkSurface for GPU, we'd immediately need to get the pixels back. + if (!mXorCanvas) + { + // Use unpremultiplied alpha (see xor applying in applyXor()). + if (!mXorBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) + abort(); + mXorBitmap.eraseARGB(0, 0, 0, 0); + mXorCanvas = std::make_unique(mXorBitmap); + setCanvasClipRegion(mXorCanvas.get(), mClipRegion); + } + return mXorCanvas.get(); +} + +void SkiaSalGraphicsImpl::applyXor() +{ + // Apply the result from the temporary bitmap manually. This is indeed + // slow, but it doesn't seem to be needed often and is optimized + // in each operation by extending mXorRegion with the area that should be + // updated. + assert(mXorMode); + if (!mSurface || !mXorCanvas + || !mXorRegion.op(SkIRect::MakeXYWH(0, 0, mSurface->width(), mSurface->height()), + SkRegion::kIntersect_Op)) + { + mXorRegion.setEmpty(); + return; + } + SAL_INFO("vcl.skia.trace", "applyxor(" << this << "): " << mXorRegion); + // Copy the surface contents to another pixmap. + SkBitmap surfaceBitmap; + // Use unpremultiplied alpha format, so that we do not have to do the conversions to get + // the RGB and back (Skia will do it when converting, but it'll be presumably faster at it). + if (!surfaceBitmap.tryAllocPixels(mSurface->imageInfo().makeAlphaType(kUnpremul_SkAlphaType))) + abort(); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is + SkCanvas canvas(surfaceBitmap); + canvas.drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), mXorRegion.getBounds(), + SkRect::Make(mXorRegion.getBounds()), &paint); + // xor to surfaceBitmap + assert(surfaceBitmap.info().alphaType() == kUnpremul_SkAlphaType); + assert(mXorBitmap.info().alphaType() == kUnpremul_SkAlphaType); + assert(surfaceBitmap.bytesPerPixel() == 4); + assert(mXorBitmap.bytesPerPixel() == 4); + for (SkRegion::Iterator it(mXorRegion); !it.done(); it.next()) + { + for (int y = it.rect().top(); y < it.rect().bottom(); ++y) + { + uint8_t* data = static_cast(surfaceBitmap.getAddr(it.rect().x(), y)); + const uint8_t* xordata = static_cast(mXorBitmap.getAddr(it.rect().x(), y)); + for (int x = 0; x < it.rect().width(); ++x) + { + *data++ ^= *xordata++; + *data++ ^= *xordata++; + *data++ ^= *xordata++; + // alpha is not xor-ed + data++; + xordata++; + } + } + } + surfaceBitmap.notifyPixelsChanged(); + mSurface->getCanvas()->drawBitmapRect(surfaceBitmap, mXorRegion.getBounds(), + SkRect::Make(mXorRegion.getBounds()), &paint); + mXorCanvas.reset(); + mXorBitmap.reset(); + mXorRegion.setEmpty(); +} + +void SkiaSalGraphicsImpl::SetROPLineColor(SalROPColor nROPColor) +{ + checkPendingDrawing(); + switch (nROPColor) + { + case SalROPColor::N0: + mLineColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + mLineColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + mLineColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void SkiaSalGraphicsImpl::SetROPFillColor(SalROPColor nROPColor) +{ + checkPendingDrawing(); + switch (nROPColor) + { + case SalROPColor::N0: + mFillColor = Color(0, 0, 0); + break; + case SalROPColor::N1: + mFillColor = Color(0xff, 0xff, 0xff); + break; + case SalROPColor::Invert: + mFillColor = Color(0xff, 0xff, 0xff); + break; + } +} + +void SkiaSalGraphicsImpl::drawPixel(long nX, long nY) { drawPixel(nX, nY, mLineColor); } + +void SkiaSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor) +{ + if (nColor == SALCOLOR_NONE) + return; + preDraw(); + SAL_INFO("vcl.skia.trace", "drawpixel(" << this << "): " << Point(nX, nY) << ":" << nColor); + addXorRegion(SkRect::MakeXYWH(nX, nY, 1, 1)); + SkPaint paint; + paint.setColor(toSkColor(nColor)); + // Apparently drawPixel() is actually expected to set the pixel and not draw it. + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + getDrawCanvas()->drawPoint(toSkX(nX), toSkY(nY), paint); + postDraw(); +} + +void SkiaSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2) +{ + if (mLineColor == SALCOLOR_NONE) + return; + preDraw(); + SAL_INFO("vcl.skia.trace", "drawline(" << this << "): " << Point(nX1, nY1) << "->" + << Point(nX2, nY2) << ":" << mLineColor); + addXorRegion(SkRect::MakeLTRB(nX1, nY1, nX2, nY2).makeSorted()); + SkPaint paint; + paint.setColor(toSkColor(mLineColor)); + paint.setAntiAlias(mParent.getAntiAliasB2DDraw()); + getDrawCanvas()->drawLine(toSkX(nX1), toSkY(nY1), toSkX(nX2), toSkY(nY2), paint); + postDraw(); +} + +void SkiaSalGraphicsImpl::privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, + double fTransparency, bool blockAA) +{ + preDraw(); + SAL_INFO("vcl.skia.trace", + "privatedrawrect(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight) + << ":" << mLineColor << ":" << mFillColor << ":" << fTransparency); + addXorRegion(SkRect::MakeXYWH(nX, nY, nWidth, nHeight)); + SkCanvas* canvas = getDrawCanvas(); + SkPaint paint; + paint.setAntiAlias(!blockAA && mParent.getAntiAliasB2DDraw()); + if (mFillColor != SALCOLOR_NONE) + { + paint.setColor(toSkColorWithTransparency(mFillColor, fTransparency)); + paint.setStyle(SkPaint::kFill_Style); + // HACK: If the polygon is just a line, it still should be drawn. But when filling + // Skia doesn't draw empty polygons, so in that case ensure the line is drawn. + if (mLineColor == SALCOLOR_NONE && SkSize::Make(nWidth, nHeight).isEmpty()) + paint.setStyle(SkPaint::kStroke_Style); + canvas->drawIRect(SkIRect::MakeXYWH(nX, nY, nWidth, nHeight), paint); + } + if (mLineColor != SALCOLOR_NONE) + { + paint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); + paint.setStyle(SkPaint::kStroke_Style); + // The obnoxious "-1 DrawRect()" hack that I don't understand the purpose of (and I'm not sure + // if anybody does), but without it some cases do not work. The max() is needed because Skia + // will not draw anything if width or height is 0. + canvas->drawIRect( + SkIRect::MakeXYWH(nX, nY, std::max(1L, nWidth - 1), std::max(1L, nHeight - 1)), paint); + } + postDraw(); +} + +void SkiaSalGraphicsImpl::drawRect(long nX, long nY, long nWidth, long nHeight) +{ + privateDrawAlphaRect(nX, nY, nWidth, nHeight, 0.0, true); +} + +void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + aPolygon.setClosed(false); + + drawPolyLine(basegfx::B2DHomMatrix(), aPolygon, 0.0, 1.0, nullptr, basegfx::B2DLineJoin::Miter, + css::drawing::LineCap_BUTT, basegfx::deg2rad(15.0) /*default*/, false); +} + +void SkiaSalGraphicsImpl::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) +{ + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pPtAry->mnX, pPtAry->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY)); + + drawPolyPolygon(basegfx::B2DHomMatrix(), basegfx::B2DPolyPolygon(aPolygon), 0.0); +} + +void SkiaSalGraphicsImpl::drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry) +{ + basegfx::B2DPolyPolygon aPolyPolygon; + for (sal_uInt32 nPolygon = 0; nPolygon < nPoly; ++nPolygon) + { + sal_uInt32 nPoints = pPoints[nPolygon]; + if (nPoints) + { + PCONSTSALPOINT pSalPoints = pPtAry[nPolygon]; + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pSalPoints->mnX, pSalPoints->mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + aPolygon.setB2DPoint(i, basegfx::B2DPoint(pSalPoints[i].mnX, pSalPoints[i].mnY)); + + aPolyPolygon.append(aPolygon); + } + } + + drawPolyPolygon(basegfx::B2DHomMatrix(), aPolyPolygon, 0.0); +} + +bool SkiaSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolyPolygon& rPolyPolygon, + double fTransparency) +{ + const bool bHasFill(mFillColor != SALCOLOR_NONE); + const bool bHasLine(mLineColor != SALCOLOR_NONE); + + if (rPolyPolygon.count() == 0 || !(bHasFill || bHasLine) || fTransparency < 0.0 + || fTransparency >= 1.0) + return true; + + basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon); + aPolyPolygon.transform(rObjectToDevice); + + SAL_INFO("vcl.skia.trace", "drawpolypolygon(" << this << "): " << aPolyPolygon << ":" + << mLineColor << ":" << mFillColor); + + if (delayDrawPolyPolygon(aPolyPolygon, fTransparency)) + { + scheduleFlush(); + return true; + } + + performDrawPolyPolygon(aPolyPolygon, fTransparency, mParent.getAntiAliasB2DDraw()); + return true; +} + +void SkiaSalGraphicsImpl::performDrawPolyPolygon(const basegfx::B2DPolyPolygon& aPolyPolygon, + double fTransparency, bool useAA) +{ + preDraw(); + + SkPath polygonPath; + bool hasOnlyOrthogonal = true; + addPolyPolygonToPath(aPolyPolygon, polygonPath, &hasOnlyOrthogonal); + polygonPath.setFillType(SkPathFillType::kEvenOdd); + addXorRegion(polygonPath.getBounds()); + + SkPaint aPaint; + aPaint.setAntiAlias(useAA); + + // For lines we use toSkX()/toSkY() in order to pass centers of pixels to Skia, + // as that leads to better results with floating-point coordinates + // (e.g. https://bugs.chromium.org/p/skia/issues/detail?id=9611). + // But that means that we generally need to use it also for areas, so that they + // line up properly if used together (tdf#134346). + // On the other hand, with AA enabled and rectangular areas, this leads to fuzzy + // edges (tdf#137329). But since rectangular areas line up perfectly to pixels + // everywhere, it shouldn't be necessary to do this for them. + // So if AA is enabled, avoid this fixup for rectangular areas. + if (!useAA || !hasOnlyOrthogonal) + { + // We normally use pixel at their center positions, but slightly off (see toSkX/Y()). + // With AA lines that "slightly off" causes tiny changes of color, making some tests + // fail. Since moving AA-ed line slightly to a side doesn't cause any real visual + // difference, just place exactly at the center. tdf#134346 + const SkScalar posFix = useAA ? toSkXYFix : 0; + polygonPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, nullptr); + } + if (mFillColor != SALCOLOR_NONE) + { + aPaint.setColor(toSkColorWithTransparency(mFillColor, fTransparency)); + aPaint.setStyle(SkPaint::kFill_Style); + // HACK: If the polygon is just a line, it still should be drawn. But when filling + // Skia doesn't draw empty polygons, so in that case ensure the line is drawn. + if (mLineColor == SALCOLOR_NONE && polygonPath.getBounds().isEmpty()) + aPaint.setStyle(SkPaint::kStroke_Style); + getDrawCanvas()->drawPath(polygonPath, aPaint); + } + if (mLineColor != SALCOLOR_NONE) + { + aPaint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); + aPaint.setStyle(SkPaint::kStroke_Style); + getDrawCanvas()->drawPath(polygonPath, aPaint); + } + postDraw(); +#if defined LINUX + // WORKAROUND: The logo in the about dialog has drawing errors. This seems to happen + // only on Linux (not Windows on the same machine), with both AMDGPU and Mesa, + // and only when antialiasing is enabled. Flushing seems to avoid the problem. + if (useAA && SkiaHelper::getVendor() == DriverBlocklist::VendorAMD) + mSurface->flushAndSubmit(); +#endif +} + +namespace +{ +struct LessThan +{ + bool operator()(const basegfx::B2DPoint& point1, const basegfx::B2DPoint& point2) const + { + if (basegfx::fTools::equal(point1.getX(), point2.getX())) + return basegfx::fTools::less(point1.getY(), point2.getY()); + return basegfx::fTools::less(point1.getX(), point2.getX()); + } +}; +} // namespace + +bool SkiaSalGraphicsImpl::delayDrawPolyPolygon(const basegfx::B2DPolyPolygon& aPolyPolygon, + double fTransparency) +{ + // There is some code that needlessly subdivides areas into adjacent rectangles, + // but Skia doesn't line them up perfectly if AA is enabled (e.g. Cairo, Qt5 do, + // but Skia devs claim it's working as intended + // https://groups.google.com/d/msg/skia-discuss/NlKpD2X_5uc/Vuwd-kyYBwAJ). + // An example is tdf#133016, which triggers SvgStyleAttributes::add_stroke() + // implementing a line stroke as a bunch of polygons instead of just one, and + // SvgLinearAtomPrimitive2D::create2DDecomposition() creates a gradient + // as a series of polygons of gradually changing color. Those places should be + // changed, but try to merge those split polygons back into the original one, + // where the needlessly created edges causing problems will not exist. + // This means drawing of such polygons needs to be delayed, so that they can + // be possibly merged with the next one. + // Merge only polygons of the same properties (color, etc.), so the gradient problem + // actually isn't handled here. + + // Only AA polygons need merging, because they do not line up well because of the AA of the edges. + if (!mParent.getAntiAliasB2DDraw()) + return false; + // Only filled polygons without an outline are problematic. + if (mFillColor == SALCOLOR_NONE || mLineColor != SALCOLOR_NONE) + return false; + // Merge only simple polygons, real polypolygons most likely aren't needlessly split, + // so they do not need joining. + if (aPolyPolygon.count() != 1) + return false; + // If the polygon is not closed, it doesn't mark an area to be filled. + if (!aPolyPolygon.isClosed()) + return false; + // If a polygon does not contain a straight line, i.e. it's all curves, then do not merge. + // First of all that's even more expensive, and second it's very unlikely that it's a polygon + // split into more polygons. + if (!polygonContainsLine(aPolyPolygon)) + return false; + + if (mLastPolyPolygonInfo.polygons.size() != 0 + && (mLastPolyPolygonInfo.transparency != fTransparency + || !mLastPolyPolygonInfo.bounds.overlaps(aPolyPolygon.getB2DRange()))) + { + checkPendingDrawing(); // Cannot be parts of the same larger polygon, draw the last and reset. + } + if (!mLastPolyPolygonInfo.polygons.empty()) + { + assert(aPolyPolygon.count() == 1); + assert(mLastPolyPolygonInfo.polygons.back().count() == 1); + // Check if the new and the previous polygon share at least one point. If not, then they + // cannot be adjacent polygons, so there's no point in trying to merge them. + bool sharePoint = false; + const basegfx::B2DPolygon& poly1 = aPolyPolygon.getB2DPolygon(0); + const basegfx::B2DPolygon& poly2 = mLastPolyPolygonInfo.polygons.back().getB2DPolygon(0); + o3tl::sorted_vector poly1Points; // for O(n log n) + poly1Points.reserve(poly1.count()); + for (sal_uInt32 i = 0; i < poly1.count(); ++i) + poly1Points.insert(poly1.getB2DPoint(i)); + for (sal_uInt32 i = 0; i < poly2.count(); ++i) + if (poly1Points.find(poly2.getB2DPoint(i)) != poly1Points.end()) + { + sharePoint = true; + break; + } + if (!sharePoint) + checkPendingDrawing(); // Draw the previous one and reset. + } + // Collect the polygons that can be possibly merged. Do the merging only once at the end, + // because it's not a cheap operation. + mLastPolyPolygonInfo.polygons.push_back(aPolyPolygon); + mLastPolyPolygonInfo.bounds.expand(aPolyPolygon.getB2DRange()); + mLastPolyPolygonInfo.transparency = fTransparency; + return true; +} + +void SkiaSalGraphicsImpl::checkPendingDrawing() +{ + if (mLastPolyPolygonInfo.polygons.size() != 0) + { // Flush any pending polygon drawing. + basegfx::B2DPolyPolygonVector polygons; + std::swap(polygons, mLastPolyPolygonInfo.polygons); + double transparency = mLastPolyPolygonInfo.transparency; + mLastPolyPolygonInfo.bounds.reset(); + if (polygons.size() == 1) + performDrawPolyPolygon(polygons.front(), transparency, true); + else + // TODO: tdf#136222 shows that basegfx::utils::mergeToSinglePolyPolygon() is unreliable + // in corner cases, possibly either a bug or rounding errors somewhere. + performDrawPolyPolygon(basegfx::utils::mergeToSinglePolyPolygon(polygons), transparency, + true); + } +} + +bool SkiaSalGraphicsImpl::drawPolyLine(const basegfx::B2DHomMatrix& rObjectToDevice, + const basegfx::B2DPolygon& rPolyLine, double fTransparency, + double fLineWidth, const std::vector* pStroke, + basegfx::B2DLineJoin eLineJoin, + css::drawing::LineCap eLineCap, double fMiterMinimumAngle, + bool bPixelSnapHairline) +{ + if (!rPolyLine.count() || fTransparency < 0.0 || fTransparency > 1.0 + || mLineColor == SALCOLOR_NONE) + { + return true; + } + + preDraw(); + SAL_INFO("vcl.skia.trace", "drawpolyline(" << this << "): " << rPolyLine << ":" << mLineColor); + + // tdf#124848 get correct LineWidth in discrete coordinates, + if (fLineWidth == 0) // hairline + fLineWidth = 1.0; + else // Adjust line width for object-to-device scale. + fLineWidth = (rObjectToDevice * basegfx::B2DVector(fLineWidth, 0)).getLength(); + + // Transform to DeviceCoordinates, get DeviceLineWidth, execute PixelSnapHairline + basegfx::B2DPolyPolygon aPolyPolygonLine; + aPolyPolygonLine.append(rPolyLine); + aPolyPolygonLine.transform(rObjectToDevice); + if (bPixelSnapHairline) + { + aPolyPolygonLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygonLine); + } + + // Setup Line Join + SkPaint::Join eSkLineJoin = SkPaint::kMiter_Join; + switch (eLineJoin) + { + case basegfx::B2DLineJoin::Bevel: + eSkLineJoin = SkPaint::kBevel_Join; + break; + case basegfx::B2DLineJoin::Round: + eSkLineJoin = SkPaint::kRound_Join; + break; + case basegfx::B2DLineJoin::NONE: + case basegfx::B2DLineJoin::Miter: + eSkLineJoin = SkPaint::kMiter_Join; + break; + } + + // convert miter minimum angle to miter limit + double fMiterLimit = 1.0 / std::sin(fMiterMinimumAngle / 2.0); + + // Setup Line Cap + SkPaint::Cap eSkLineCap(SkPaint::kButt_Cap); + + switch (eLineCap) + { + case css::drawing::LineCap_ROUND: + eSkLineCap = SkPaint::kRound_Cap; + break; + case css::drawing::LineCap_SQUARE: + eSkLineCap = SkPaint::kSquare_Cap; + break; + default: // css::drawing::LineCap_BUTT: + eSkLineCap = SkPaint::kButt_Cap; + break; + } + + SkPaint aPaint; + aPaint.setStyle(SkPaint::kStroke_Style); + aPaint.setStrokeCap(eSkLineCap); + aPaint.setStrokeJoin(eSkLineJoin); + aPaint.setColor(toSkColorWithTransparency(mLineColor, fTransparency)); + aPaint.setStrokeMiter(fMiterLimit); + aPaint.setStrokeWidth(fLineWidth); + aPaint.setAntiAlias(mParent.getAntiAliasB2DDraw()); + // See the tdf#134346 comment above. + const SkScalar posFix = mParent.getAntiAliasB2DDraw() ? toSkXYFix : 0; + + if (pStroke && std::accumulate(pStroke->begin(), pStroke->end(), 0.0) != 0) + { + std::vector intervals; + // Transform size by the matrix. + for (double stroke : *pStroke) + intervals.push_back((rObjectToDevice * basegfx::B2DVector(stroke, 0)).getLength()); + aPaint.setPathEffect(SkDashPathEffect::Make(intervals.data(), intervals.size(), 0)); + } + + // Skia does not support basegfx::B2DLineJoin::NONE, so in that case batch only if lines + // are not wider than a pixel. + if (eLineJoin != basegfx::B2DLineJoin::NONE || fLineWidth <= 1.0) + { + SkPath aPath; + aPath.setFillType(SkPathFillType::kEvenOdd); + for (sal_uInt32 a(0); a < aPolyPolygonLine.count(); a++) + addPolygonToPath(aPolyPolygonLine.getB2DPolygon(a), aPath); + aPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, nullptr); + addXorRegion(aPath.getBounds()); + getDrawCanvas()->drawPath(aPath, aPaint); + } + else + { + for (sal_uInt32 i = 0; i < aPolyPolygonLine.count(); ++i) + { + const basegfx::B2DPolygon& rPolygon = aPolyPolygonLine.getB2DPolygon(i); + sal_uInt32 nPoints = rPolygon.count(); + bool bClosed = rPolygon.isClosed(); + for (sal_uInt32 j = 0; j < (bClosed ? nPoints : nPoints - 1); ++j) + { + sal_uInt32 index1 = (j + 0) % nPoints; + sal_uInt32 index2 = (j + 1) % nPoints; + SkPath aPath; + aPath.moveTo(rPolygon.getB2DPoint(index1).getX(), + rPolygon.getB2DPoint(index1).getY()); + aPath.lineTo(rPolygon.getB2DPoint(index2).getX(), + rPolygon.getB2DPoint(index2).getY()); + + aPath.offset(toSkX(0) + posFix, toSkY(0) + posFix, nullptr); + addXorRegion(aPath.getBounds()); + getDrawCanvas()->drawPath(aPath, aPaint); + } + } + } + + postDraw(); + + return true; +} + +bool SkiaSalGraphicsImpl::drawPolyLineBezier(sal_uInt32, const SalPoint*, const PolyFlags*) +{ + // TODO? + return false; +} + +bool SkiaSalGraphicsImpl::drawPolygonBezier(sal_uInt32, const SalPoint*, const PolyFlags*) +{ + // TODO? + return false; +} + +bool SkiaSalGraphicsImpl::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32*, + const SalPoint* const*, const PolyFlags* const*) +{ + // TODO? + return false; +} + +static void copyArea(SkCanvas* canvas, sk_sp surface, long nDestX, long nDestY, + long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, bool srcIsRaster, + bool destIsRaster) +{ + // Using SkSurface::draw() should be more efficient than SkSurface::makeImageSnapshot(), + // because it may detect copying to itself and avoid some needless copies. + // But it has problems with drawing to itself + // (https://groups.google.com/forum/#!topic/skia-discuss/6yiuw24jv0I) and also + // raster surfaces do not avoid a copy of the source + // (https://groups.google.com/forum/#!topic/skia-discuss/S3FMpCi82k0). + // Finally, there's not much point if one of them is raster and the other is not (chrome/m86 even crashes). + if (canvas == surface->getCanvas() || srcIsRaster || (srcIsRaster != destIsRaster)) + { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + canvas->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), + SkIRect::MakeXYWH(nSrcX, nSrcY, nSrcWidth, nSrcHeight), + SkRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight), &paint); + return; + } + // SkCanvas::draw() cannot do a subrectangle, so clip. + canvas->save(); + canvas->clipRect(SkRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + surface->draw(canvas, nDestX - nSrcX, nDestY - nSrcY, &paint); + canvas->restore(); +} + +void SkiaSalGraphicsImpl::copyArea(long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, bool /*bWindowInvalidate*/) +{ + if (nDestX == nSrcX && nDestY == nSrcY) + return; + preDraw(); + SAL_INFO("vcl.skia.trace", "copyarea(" + << this << "): " << Point(nSrcX, nSrcY) << "->" + << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)); + assert(!mXorMode); + ::copyArea(getDrawCanvas(), mSurface, nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, + !isGPU(), !isGPU()); + postDraw(); +} + +void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics) +{ + preDraw(); + SkiaSalGraphicsImpl* src; + if (pSrcGraphics) + { + assert(dynamic_cast(pSrcGraphics->GetImpl())); + src = static_cast(pSrcGraphics->GetImpl()); + src->checkSurface(); + src->flushDrawing(); + } + else + { + src = this; + assert(!mXorMode); + } + if (rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) + { + auto srcDebug = [&]() -> std::string { + if (src == this) + return "(self)"; + else + { + std::ostringstream stream; + stream << "(" << src << ")"; + return stream.str(); + } + }; + SAL_INFO("vcl.skia.trace", + "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry); + ::copyArea(getDrawCanvas(), src->mSurface, rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, + rPosAry.mnSrcY, rPosAry.mnDestWidth, rPosAry.mnDestHeight, !src->isGPU(), + !isGPU()); + } + else + { + SAL_INFO("vcl.skia.trace", "copybits(" << this << "): (" << src << "): " << rPosAry); + // Do not use makeImageSnapshot(rect), as that one may make a needless data copy. + sk_sp image = SkiaHelper::makeCheckedImageSnapshot(src->mSurface); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth + || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + paint.setFilterQuality(kHigh_SkFilterQuality); + getDrawCanvas()->drawImageRect(image, + SkIRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight), + SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, + rPosAry.mnDestWidth, rPosAry.mnDestHeight), + &paint); + } + assert(!mXorMode); + postDraw(); +} + +bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect& rPosAry, const SalBitmap& rBitmap) +{ + if (checkInvalidSourceOrDestination(rPosAry)) + return false; + + assert(dynamic_cast(&rBitmap)); + const SkiaSalBitmap& rSkiaBitmap = static_cast(rBitmap); + // This is used by VirtualDevice in the alpha mode for the "alpha" layer which + // is actually one-minus-alpha (opacity). Therefore white=0xff=transparent, + // black=0x00=opaque. So the result is transparent only if both the inputs + // are transparent. Since for blending operations white=1.0 and black=0.0, + // kMultiply should handle exactly that (transparent*transparent=transparent, + // opaque*transparent=opaque). And guessing from the "floor" in TYPE_BLEND in opengl's + // combinedTextureFragmentShader.glsl, the layer is not even alpha values but + // simply yes-or-no mask. + // See also blendAlphaBitmap(). + drawImage(rPosAry, rSkiaBitmap.GetSkImage(), SkBlendMode::kMultiply); + return true; +} + +bool SkiaSalGraphicsImpl::blendAlphaBitmap(const SalTwoRect& rPosAry, + const SalBitmap& rSourceBitmap, + const SalBitmap& rMaskBitmap, + const SalBitmap& rAlphaBitmap) +{ + if (checkInvalidSourceOrDestination(rPosAry)) + return false; + + assert(dynamic_cast(&rSourceBitmap)); + assert(dynamic_cast(&rMaskBitmap)); + assert(dynamic_cast(&rAlphaBitmap)); + const SkiaSalBitmap& rSkiaSourceBitmap = static_cast(rSourceBitmap); + const SkiaSalBitmap& rSkiaMaskBitmap = static_cast(rMaskBitmap); + const SkiaSalBitmap& rSkiaAlphaBitmap = static_cast(rAlphaBitmap); + + // This was originally implemented for the OpenGL drawing method and it is poorly documented. + // The source and mask bitmaps are the usual data and alpha bitmaps, and 'alpha' + // is the "alpha" layer of the VirtualDevice (the alpha in VirtualDevice is also stored + // as a separate bitmap). Now if I understand it correctly these two alpha masks first need + // to be combined into the actual alpha mask to be used. The formula for TYPE_BLEND + // in opengl's combinedTextureFragmentShader.glsl is + // "result_alpha = 1.0 - (1.0 - floor(alpha)) * mask". + // See also blendBitmap(). + + // First do the "( 1 - alpha ) * mask" + // (no idea how to do "floor", but hopefully not needed in practice). + sk_sp shaderAlpha + = SkShaders::Blend(SkBlendMode::kDstOut, rSkiaMaskBitmap.GetAlphaSkImage()->makeShader(), + rSkiaAlphaBitmap.GetAlphaSkImage()->makeShader()); + // And now draw the bitmap with "1 - x", where x is the "( 1 - alpha ) * mask". + sk_sp shader = SkShaders::Blend(SkBlendMode::kSrcOut, shaderAlpha, + rSkiaSourceBitmap.GetSkImage()->makeShader()); + drawShader(rPosAry, shader); + return true; +} + +void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) +{ + if (checkInvalidSourceOrDestination(rPosAry)) + return; + + assert(dynamic_cast(&rSalBitmap)); + const SkiaSalBitmap& rSkiaSourceBitmap = static_cast(rSalBitmap); + + drawImage(rPosAry, rSkiaSourceBitmap.GetSkImage()); +} + +void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap) +{ + drawAlphaBitmap(rPosAry, rSalBitmap, rMaskBitmap); +} + +void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, + Color nMaskColor) +{ + assert(dynamic_cast(&rSalBitmap)); + const SkiaSalBitmap& skiaBitmap = static_cast(rSalBitmap); + drawShader(rPosAry, + SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. + SkShaders::Color(toSkColor(nMaskColor)), + skiaBitmap.GetAlphaSkImage()->makeShader())); +} + +std::shared_ptr SkiaSalGraphicsImpl::getBitmap(long nX, long nY, long nWidth, + long nHeight) +{ + SkiaZone zone; + checkSurface(); + SAL_INFO("vcl.skia.trace", + "getbitmap(" << this << "): " << SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)); + flushDrawing(); + // TODO makeImageSnapshot(rect) may copy the data, which may be a waste if this is used + // e.g. for VirtualDevice's lame alpha blending, in which case the image will eventually end up + // in blendAlphaBitmap(), where we could simply use the proper rect of the image. + sk_sp image = SkiaHelper::makeCheckedImageSnapshot( + mSurface, SkIRect::MakeXYWH(nX, nY, nWidth, nHeight)); + return std::make_shared(image); +} + +Color SkiaSalGraphicsImpl::getPixel(long nX, long nY) +{ + SkiaZone zone; + checkSurface(); + SAL_INFO("vcl.skia.trace", "getpixel(" << this << "): " << Point(nX, nY)); + flushDrawing(); + // This is presumably slow, but getPixel() should be generally used only by unit tests. + SkBitmap bitmap; + if (!bitmap.tryAllocN32Pixels(GetWidth(), GetHeight())) + abort(); + if (!mSurface->readPixels(bitmap, 0, 0)) + abort(); + return fromSkColor(bitmap.getColor(nX, nY)); +} + +void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFlags) +{ + preDraw(); + SAL_INFO("vcl.skia.trace", "invert(" << this << "): " << rPoly << ":" << int(eFlags)); + assert(!mXorMode); + // Intel Vulkan drivers (up to current 0.401.3889) have a problem + // with SkBlendMode::kDifference(?) and surfaces wider than 1024 pixels, resulting + // in drawing errors. Work that around by fetching the relevant part of the surface + // and drawing using CPU. + bool intelHack + = (isGPU() && SkiaHelper::getVendor() == DriverBlocklist::VendorIntel && !mXorMode); + // TrackFrame just inverts a dashed path around the polygon + if (eFlags == SalInvert::TrackFrame) + { + SkPath aPath; + addPolygonToPath(rPoly, aPath); + aPath.setFillType(SkPathFillType::kEvenOdd); + // TrackFrame is not supposed to paint outside of the polygon (usually rectangle), + // but wider stroke width usually results in that, so ensure the requirement + // by clipping. + SkAutoCanvasRestore autoRestore(getDrawCanvas(), true); + getDrawCanvas()->clipRect(aPath.getBounds(), SkClipOp::kIntersect, false); + SkPaint aPaint; + aPaint.setStrokeWidth(2); + float intervals[] = { 4.0f, 4.0f }; + aPaint.setStyle(SkPaint::kStroke_Style); + aPaint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0)); + aPaint.setColor(SkColorSetARGB(255, 255, 255, 255)); + aPaint.setBlendMode(SkBlendMode::kDifference); + if (!intelHack) + getDrawCanvas()->drawPath(aPath, aPaint); + else + { + SkRect area; + aPath.getBounds().roundOut(&area); + SkRect size = SkRect::MakeWH(area.width(), area.height()); + sk_sp surface = SkSurface::MakeRasterN32Premul(area.width(), area.height()); + SkPaint copy; + copy.setBlendMode(SkBlendMode::kSrc); + flushDrawing(); + surface->getCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), + area, size, ©); + aPath.offset(-area.x(), -area.y()); + surface->getCanvas()->drawPath(aPath, aPaint); + getDrawCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), size, + area, ©); + } + } + else + { + SkPath aPath; + addPolygonToPath(rPoly, aPath); + aPath.setFillType(SkPathFillType::kEvenOdd); + SkPaint aPaint; + aPaint.setColor(SkColorSetARGB(255, 255, 255, 255)); + aPaint.setStyle(SkPaint::kFill_Style); + aPaint.setBlendMode(SkBlendMode::kDifference); + + // N50 inverts in checker pattern + if (eFlags == SalInvert::N50) + { + // This creates 2x2 checker pattern bitmap + // TODO Use SkiaHelper::createSkSurface() and cache the image + SkBitmap aBitmap; + aBitmap.allocN32Pixels(2, 2); + const SkPMColor white = SkPreMultiplyARGB(0xFF, 0xFF, 0xFF, 0xFF); + const SkPMColor black = SkPreMultiplyARGB(0xFF, 0x00, 0x00, 0x00); + SkPMColor* scanline; + scanline = aBitmap.getAddr32(0, 0); + *scanline++ = white; + *scanline++ = black; + scanline = aBitmap.getAddr32(0, 1); + *scanline++ = black; + *scanline++ = white; + aBitmap.setImmutable(); + // The bitmap is repeated in both directions the checker pattern is as big + // as the polygon (usually rectangle) + aPaint.setShader(aBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat)); + } + if (!intelHack) + getDrawCanvas()->drawPath(aPath, aPaint); + else + { + SkRect area; + aPath.getBounds().roundOut(&area); + SkRect size = SkRect::MakeWH(area.width(), area.height()); + sk_sp surface = SkSurface::MakeRasterN32Premul(area.width(), area.height()); + SkPaint copy; + copy.setBlendMode(SkBlendMode::kSrc); + flushDrawing(); + surface->getCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(mSurface), + area, size, ©); + aPath.offset(-area.x(), -area.y()); + surface->getCanvas()->drawPath(aPath, aPaint); + getDrawCanvas()->drawImageRect(SkiaHelper::makeCheckedImageSnapshot(surface), size, + area, ©); + } + } + postDraw(); +} + +void SkiaSalGraphicsImpl::invert(long nX, long nY, long nWidth, long nHeight, SalInvert eFlags) +{ + basegfx::B2DRectangle aRectangle(nX, nY, nX + nWidth, nY + nHeight); + auto aRect = basegfx::utils::createPolygonFromRect(aRectangle); + invert(aRect, eFlags); +} + +void SkiaSalGraphicsImpl::invert(sal_uInt32 nPoints, const SalPoint* pPointArray, SalInvert eFlags) +{ + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pPointArray[0].mnX, pPointArray[0].mnY), nPoints); + for (sal_uInt32 i = 1; i < nPoints; ++i) + { + aPolygon.setB2DPoint(i, basegfx::B2DPoint(pPointArray[i].mnX, pPointArray[i].mnY)); + } + aPolygon.setClosed(true); + + invert(aPolygon, eFlags); +} + +bool SkiaSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uInt32) +{ + // TODO? + return false; +} + +// Create SkImage from a bitmap and possibly an alpha mask (the usual VCL one-minus-alpha), +// with the given target size. Result will be possibly cached, unless disabled. +sk_sp SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitmap, + const SkiaSalBitmap* alphaBitmap, + const Size targetSize) +{ + sk_sp image; + // GPU-accelerated drawing with SkShader should be fast enough to not need caching. + if (isGPU()) + return image; + if (targetSize.IsEmpty()) + return image; + // Probably not much point in caching of just doing a copy. + if (alphaBitmap == nullptr && targetSize == bitmap.GetSize()) + return image; + // Image too small to be worth caching. + if (bitmap.GetSize().Width() < 100 && bitmap.GetSize().Height() < 100 + && targetSize.Width() < 100 && targetSize.Height() < 100) + return image; + // In some cases (tdf#134237) the draw size may be very large. In that case it's + // better to rely on Skia to clip and draw only the necessary, rather than prepare + // a very large image only to not use most of it. + if (targetSize.Width() > GetWidth() || targetSize.Height() > GetHeight()) + { + // This is a bit tricky. The condition above just checks that at least a part of the resulting + // image will not be used (it's larger then our drawing area). But this may often happen + // when just scrolling a document with a large image, where the caching may very well be worth it. + // Since the problem is mainly the cost of upscaling and then the size of the resulting bitmap, + // compute a ratio of how much this is going to be scaled up, how much this is larger than + // the drawing area, and then refuse to cache if it's too much. + const double upscaleRatio = 1.0 * targetSize.Width() / bitmap.GetSize().Width() + * targetSize.Height() / bitmap.GetSize().Height(); + const double oversizeRatio + = 1.0 * targetSize.Width() / GetWidth() * targetSize.Height() / GetHeight(); + const double ratio = upscaleRatio * oversizeRatio; + if (ratio > 10) + { + SAL_INFO("vcl.skia.trace", "mergecachebitmaps(" + << this << "): not caching upscaling, ratio:" << ratio + << ", " << bitmap.GetSize() << "->" << targetSize + << " in " << Size(GetWidth(), GetHeight())); + return image; + } + } + OString key; + OStringBuffer keyBuf; + keyBuf.append(targetSize.Width()) + .append("x") + .append(targetSize.Height()) + .append("_0x") + .append(reinterpret_cast(&bitmap), 16) + .append("_0x") + .append(reinterpret_cast(alphaBitmap), 16) + .append("_") + .append(static_cast(bitmap.GetSkImage()->uniqueID())); + if (alphaBitmap) + keyBuf.append("_").append( + static_cast(alphaBitmap->GetAlphaSkImage()->uniqueID())); + key = keyBuf.makeStringAndClear(); + image = SkiaHelper::findCachedImage(key); + if (image) + { + assert(image->width() == targetSize.Width() && image->height() == targetSize.Height()); + return image; + } + // Combine bitmap + alpha bitmap into one temporary bitmap with alpha. + // If scaling is needed, first apply the alpha, then scale, otherwise the scaling might affect the alpha values. + if (alphaBitmap && targetSize != bitmap.GetSize()) + { + sk_sp mergedSurface = SkiaHelper::createSkSurface(bitmap.GetSize()); + if (!mergedSurface) + return nullptr; + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + mergedSurface->getCanvas()->drawImage(bitmap.GetSkImage(), 0, 0, &paint); + paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha + mergedSurface->getCanvas()->drawImage(alphaBitmap->GetAlphaSkImage(), 0, 0, &paint); + sk_sp scaledSurface = SkiaHelper::createSkSurface(targetSize); + if (!scaledSurface) + return nullptr; + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + paint.setFilterQuality(kHigh_SkFilterQuality); + scaledSurface->getCanvas()->drawImageRect( + mergedSurface->makeImageSnapshot(), + SkRect::MakeXYWH(0, 0, bitmap.GetSize().Width(), bitmap.GetSize().Height()), + SkRect::MakeXYWH(0, 0, targetSize.Width(), targetSize.Height()), &paint); + image = scaledSurface->makeImageSnapshot(); + } + else // No alpha or no scaling, scale directly. + { + sk_sp tmpSurface = SkiaHelper::createSkSurface(targetSize); + if (!tmpSurface) + return nullptr; + SkCanvas* canvas = tmpSurface->getCanvas(); + SkAutoCanvasRestore autoRestore(canvas, true); + SkPaint paint; + if (targetSize != bitmap.GetSize()) + { + SkMatrix matrix; + matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / bitmap.GetSize().Width()); + matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / bitmap.GetSize().Height()); + canvas->concat(matrix); + paint.setFilterQuality(kHigh_SkFilterQuality); + } + paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + canvas->drawImage(bitmap.GetSkImage(), 0, 0, &paint); + if (alphaBitmap != nullptr) + { + paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha + canvas->drawImage(alphaBitmap->GetAlphaSkImage(), 0, 0, &paint); + } + image = SkiaHelper::makeCheckedImageSnapshot(tmpSurface); + } + SkiaHelper::addCachedImage(key, image); + return image; +} + +bool SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap) +{ + assert(dynamic_cast(&rSourceBitmap)); + assert(dynamic_cast(&rAlphaBitmap)); + // In raster mode use mergeCacheBitmaps(), which will cache the result, avoiding repeated + // alpha blending or scaling. In GPU mode it is simpler to just use SkShader. + SalTwoRect imagePosAry(rPosAry); + Size imageSize = rSourceBitmap.GetSize(); + // If the bitmap will be scaled, prefer to do it in mergeCacheBitmaps(), if possible. + if ((rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + && rPosAry.mnSrcX == 0 && rPosAry.mnSrcY == 0 + && rPosAry.mnSrcWidth == rSourceBitmap.GetSize().Width() + && rPosAry.mnSrcHeight == rSourceBitmap.GetSize().Height()) + { + imagePosAry.mnSrcWidth = imagePosAry.mnDestWidth; + imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight; + imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight); + } + sk_sp image + = mergeCacheBitmaps(static_cast(rSourceBitmap), + static_cast(&rAlphaBitmap), imageSize); + if (image) + drawImage(imagePosAry, image); + else + drawShader( + rPosAry, + SkShaders::Blend( + SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. + static_cast(rSourceBitmap).GetSkImage()->makeShader(), + static_cast(&rAlphaBitmap)->GetAlphaSkImage()->makeShader())); + return true; +} + +void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const sk_sp& aImage, + SkBlendMode eBlendMode) +{ + SkRect aSourceRect + = SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + SkRect aDestinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, + rPosAry.mnDestWidth, rPosAry.mnDestHeight); + + SkPaint aPaint; + aPaint.setBlendMode(eBlendMode); + if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + aPaint.setFilterQuality(kHigh_SkFilterQuality); + + preDraw(); + SAL_INFO("vcl.skia.trace", + "drawimage(" << this << "): " << rPosAry << ":" << SkBlendMode_Name(eBlendMode)); + addXorRegion(aDestinationRect); + getDrawCanvas()->drawImageRect(aImage, aSourceRect, aDestinationRect, &aPaint); + postDraw(); +} + +// SkShader can be used to merge multiple bitmaps with appropriate blend modes (e.g. when +// merging a bitmap with its alpha mask). +void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const sk_sp& shader) +{ + preDraw(); + SAL_INFO("vcl.skia.trace", "drawshader(" << this << "): " << rPosAry); + SkRect destinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, + rPosAry.mnDestHeight); + addXorRegion(destinationRect); + SkPaint paint; + paint.setShader(shader); + if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != rPosAry.mnDestHeight) + paint.setFilterQuality(kHigh_SkFilterQuality); + SkCanvas* canvas = getDrawCanvas(); + // Scaling needs to be done explicitly using a matrix. + SkAutoCanvasRestore autoRestore(canvas, true); + SkMatrix matrix = SkMatrix::Translate(rPosAry.mnDestX, rPosAry.mnDestY) + * SkMatrix::Scale(1.0 * rPosAry.mnDestWidth / rPosAry.mnSrcWidth, + 1.0 * rPosAry.mnDestHeight / rPosAry.mnSrcHeight) + * SkMatrix::Translate(-rPosAry.mnSrcX, -rPosAry.mnSrcY); + assert(matrix.mapXY(rPosAry.mnSrcX, rPosAry.mnSrcY) + == SkPoint::Make(rPosAry.mnDestX, rPosAry.mnDestY)); + assert(matrix.mapXY(rPosAry.mnSrcX + rPosAry.mnSrcWidth, rPosAry.mnSrcY + rPosAry.mnSrcHeight) + == SkPoint::Make(rPosAry.mnDestX + rPosAry.mnDestWidth, + rPosAry.mnDestY + rPosAry.mnDestHeight)); + canvas->concat(matrix); + SkRect sourceRect + = SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight); + canvas->drawRect(sourceRect, paint); + postDraw(); +} + +bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + assert(dynamic_cast(&rSourceBitmap)); + assert(!pAlphaBitmap || dynamic_cast(pAlphaBitmap)); + + const SkiaSalBitmap& rSkiaBitmap = static_cast(rSourceBitmap); + const SkiaSalBitmap* pSkiaAlphaBitmap = static_cast(pAlphaBitmap); + + // Setup the image transformation, + // using the rNull, rX, rY points as destinations for the (0,0), (Width,0), (0,Height) source points. + const basegfx::B2DVector aXRel = rX - rNull; + const basegfx::B2DVector aYRel = rY - rNull; + + preDraw(); + SAL_INFO("vcl.skia.trace", "drawtransformedbitmap(" << this << "): " << rSourceBitmap.GetSize() + << " " << rNull << ":" << rX << ":" << rY); + + addXorRegion(SkRect::MakeWH(GetWidth(), GetHeight())); // can't tell, use whole area + // In raster mode scaling and alpha blending is still somewhat expensive if done repeatedly, + // so use mergeCacheBitmaps(), which will cache the result if useful. + // It is better to use SkShader if in GPU mode, if the operation is simple or if the temporary + // image would be very large. + sk_sp imageToDraw = mergeCacheBitmaps( + rSkiaBitmap, pSkiaAlphaBitmap, Size(round(aXRel.getLength()), round(aYRel.getLength()))); + if (imageToDraw) + { + SkMatrix matrix; + // Round sizes for scaling, so that sub-pixel differences don't + // trigger unnecessary scaling. Image has already been scaled + // by mergeCacheBitmaps() and we shouldn't scale here again + // unless the drawing is also skewed. + matrix.set(SkMatrix::kMScaleX, round(aXRel.getX()) / imageToDraw->width()); + matrix.set(SkMatrix::kMScaleY, round(aYRel.getY()) / imageToDraw->height()); + matrix.set(SkMatrix::kMSkewY, aXRel.getY() / imageToDraw->width()); + matrix.set(SkMatrix::kMSkewX, aYRel.getX() / imageToDraw->height()); + matrix.set(SkMatrix::kMTransX, rNull.getX()); + matrix.set(SkMatrix::kMTransY, rNull.getY()); + SkCanvas* canvas = getDrawCanvas(); + SkAutoCanvasRestore autoRestore(canvas, true); + canvas->concat(matrix); + SkPaint paint; + paint.setFilterQuality(kHigh_SkFilterQuality); + canvas->drawImage(imageToDraw, 0, 0, &paint); + } + else + { + SkMatrix matrix; + const Size aSize = rSourceBitmap.GetSize(); + matrix.set(SkMatrix::kMScaleX, aXRel.getX() / aSize.Width()); + matrix.set(SkMatrix::kMScaleY, aYRel.getY() / aSize.Height()); + matrix.set(SkMatrix::kMSkewY, aXRel.getY() / aSize.Width()); + matrix.set(SkMatrix::kMSkewX, aYRel.getX() / aSize.Height()); + matrix.set(SkMatrix::kMTransX, rNull.getX()); + matrix.set(SkMatrix::kMTransY, rNull.getY()); + SkCanvas* canvas = getDrawCanvas(); + SkAutoCanvasRestore autoRestore(canvas, true); + canvas->concat(matrix); + SkPaint paint; + paint.setFilterQuality(kHigh_SkFilterQuality); + if (pSkiaAlphaBitmap) + { + paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha. + rSkiaBitmap.GetSkImage()->makeShader(), + pSkiaAlphaBitmap->GetAlphaSkImage()->makeShader())); + canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint); + } + else + { + canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, &paint); + } + } + postDraw(); + return true; +} + +bool SkiaSalGraphicsImpl::drawAlphaRect(long nX, long nY, long nWidth, long nHeight, + sal_uInt8 nTransparency) +{ + privateDrawAlphaRect(nX, nY, nWidth, nHeight, nTransparency / 100.0); + return true; +} + +bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon&, const Gradient&) +{ + // TODO? + return false; +} + +static double toRadian(int degree10th) { return (3600 - degree10th) * M_PI / 1800.0; } +static double toCos(int degree10th) { return SkScalarCos(toRadian(degree10th)); } +static double toSin(int degree10th) { return SkScalarSin(toRadian(degree10th)); } + +void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Color textColor, + const SkFont& font, GlyphOrientation glyphOrientation) +{ + SkiaZone zone; + std::vector glyphIds; + std::vector glyphForms; + glyphIds.reserve(256); + glyphForms.reserve(256); + Point aPos; + const GlyphItem* pGlyph; + int nStart = 0; + while (layout.GetNextGlyph(&pGlyph, aPos, nStart)) + { + glyphIds.push_back(pGlyph->glyphId()); + int angle = 0; // 10th of degree + if (glyphOrientation == GlyphOrientation::Apply) + { + angle = layout.GetOrientation(); + if (pGlyph->IsVertical()) + angle += 900; // 90 degree + } + SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.X(), aPos.Y()); + glyphForms.emplace_back(std::move(form)); + } + if (glyphIds.empty()) + return; + sk_sp textBlob + = SkTextBlob::MakeFromRSXform(glyphIds.data(), glyphIds.size() * sizeof(SkGlyphID), + glyphForms.data(), font, SkTextEncoding::kGlyphID); + preDraw(); + SAL_INFO("vcl.skia.trace", + "drawtextblob(" << this << "): " << textBlob->bounds() << ":" << textColor); + addXorRegion(textBlob->bounds()); + SkPaint paint; + paint.setColor(toSkColor(textColor)); + getDrawCanvas()->drawTextBlob(textBlob, 0, 0, paint); + postDraw(); +} + +bool SkiaSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const +{ + switch (eType) + { + case OutDevSupportType::B2DDraw: + case OutDevSupportType::TransparentRect: + return true; + default: + return false; + } +} + +#ifdef DBG_UTIL +void SkiaSalGraphicsImpl::dump(const char* file) const +{ + assert(mSurface.get()); + SkiaHelper::dump(mSurface, file); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx new file mode 100644 index 000000000..0f62f7dc5 --- /dev/null +++ b/vcl/skia/salbmp.cxx @@ -0,0 +1,819 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef DBG_UTIL +#include +#define CANARY "skia-canary" +#endif + +SkiaSalBitmap::SkiaSalBitmap() {} + +SkiaSalBitmap::~SkiaSalBitmap() {} + +static bool isValidBitCount(sal_uInt16 nBitCount) +{ + return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 24) + || (nBitCount == 32); +} + +SkiaSalBitmap::SkiaSalBitmap(const sk_sp& image) +{ + ResetCachedData(); + mBuffer.reset(); + mImage = image; + mPalette = BitmapPalette(); + mBitCount = 32; + mSize = mPixelsSize = Size(image->width(), image->height()); +#ifdef DBG_UTIL + mWriteAccessCount = 0; +#endif + SAL_INFO("vcl.skia.trace", "bitmapfromimage(" << this << ")"); +} + +bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal) +{ + ResetCachedData(); + mBuffer.reset(); + if (!isValidBitCount(nBitCount)) + return false; + mPalette = rPal; + mBitCount = nBitCount; + mSize = mPixelsSize = rSize; +#ifdef DBG_UTIL + mWriteAccessCount = 0; +#endif + if (!CreateBitmapData()) + { + mBitCount = 0; + mSize = mPixelsSize = Size(); + mPalette = BitmapPalette(); + return false; + } + SAL_INFO("vcl.skia.trace", "create(" << this << ")"); + return true; +} + +bool SkiaSalBitmap::CreateBitmapData() +{ + assert(!mBuffer); + // The pixels could be stored in SkBitmap, but Skia only supports 8bit gray, 16bit and 32bit formats + // (e.g. 24bpp is actually stored as 32bpp). But some of our code accessing the bitmap assumes that + // when it asked for 24bpp, the format really will be 24bpp (e.g. the png loader), so we cannot use + // SkBitmap to store the data. And even 8bpp is problematic, since Skia does not support palettes + // and a VCL bitmap can change its grayscale status simply by changing the palette. + // Moreover creating SkImage from SkBitmap does a data copy unless the bitmap is immutable. + // So just always store pixels in our buffer and convert as necessary. + int bitScanlineWidth; + if (o3tl::checked_multiply(mSize.Width(), mBitCount, bitScanlineWidth)) + { + SAL_WARN("vcl.skia", "checked multiply failed"); + return false; + } + mScanlineSize = AlignedWidth4Bytes(bitScanlineWidth); + if (mScanlineSize != 0 && mSize.Height() != 0) + { + size_t allocate = mScanlineSize * mSize.Height(); +#ifdef DBG_UTIL + allocate += sizeof(CANARY); +#endif + mBuffer = boost::make_shared_noinit(allocate); +#ifdef DBG_UTIL + // fill with random garbage + sal_uInt8* buffer = mBuffer.get(); + for (size_t i = 0; i < allocate; i++) + buffer[i] = (i & 0xFF); + memcpy(buffer + allocate - sizeof(CANARY), CANARY, sizeof(CANARY)); +#endif + } + return true; +} + +bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp) +{ + return Create(rSalBmp, rSalBmp.GetBitCount()); +} + +bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp, SalGraphics* pGraphics) +{ + return Create(rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount()); +} + +bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount) +{ + const SkiaSalBitmap& src = static_cast(rSalBmp); + mImage = src.mImage; + mAlphaImage = src.mAlphaImage; + mBuffer = src.mBuffer; + mPalette = src.mPalette; + mBitCount = src.mBitCount; + mSize = src.mSize; + mPixelsSize = src.mPixelsSize; + mScanlineSize = src.mScanlineSize; + mScaleQuality = src.mScaleQuality; +#ifdef DBG_UTIL + mWriteAccessCount = 0; +#endif + if (nNewBitCount != src.GetBitCount()) + { + // This appears to be unused(?). Implement this just in case, but be lazy + // about it and rely on EnsureBitmapData() doing the conversion from mImage + // if needed, even if that may need unnecessary to- and from- SkImage + // conversion. + ResetToSkImage(GetSkImage()); + } + SAL_INFO("vcl.skia.trace", "create(" << this << "): (" << &src << ")"); + return true; +} + +bool SkiaSalBitmap::Create(const css::uno::Reference&, Size&, bool) +{ + // TODO? + return false; +} + +void SkiaSalBitmap::Destroy() +{ + SAL_INFO("vcl.skia.trace", "destroy(" << this << ")"); +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + ResetCachedData(); + mBuffer.reset(); +} + +Size SkiaSalBitmap::GetSize() const { return mSize; } + +sal_uInt16 SkiaSalBitmap::GetBitCount() const { return mBitCount; } + +BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode) +{ + switch (nMode) + { + case BitmapAccessMode::Write: + EnsureBitmapUniqueData(); + if (!mBuffer) + return nullptr; + break; + case BitmapAccessMode::Read: + EnsureBitmapData(); + if (!mBuffer) + return nullptr; + break; + case BitmapAccessMode::Info: + break; + } +#ifdef DBG_UTIL + // BitmapWriteAccess stores also a copy of the palette and it can + // be modified, so concurrent reading of it might result in inconsistencies. + assert(mWriteAccessCount == 0 || nMode == BitmapAccessMode::Write); +#endif + BitmapBuffer* buffer = new BitmapBuffer; + buffer->mnWidth = mSize.Width(); + buffer->mnHeight = mSize.Height(); + buffer->mnBitCount = mBitCount; + buffer->maPalette = mPalette; + buffer->mpBits = mBuffer.get(); + buffer->mnScanlineSize = mScanlineSize; + switch (mBitCount) + { + case 1: + buffer->mnFormat = ScanlineFormat::N1BitMsbPal; + break; + case 4: + buffer->mnFormat = ScanlineFormat::N4BitMsnPal; + break; + case 8: + buffer->mnFormat = ScanlineFormat::N8BitPal; + break; + case 24: + { +// Make the RGB/BGR format match the default Skia 32bpp format, to allow +// easy conversion later. +// Use a macro to hide an unreachable code warning. +#define GET_FORMAT \ + (kN32_SkColorType == kBGRA_8888_SkColorType ? ScanlineFormat::N24BitTcBgr \ + : ScanlineFormat::N24BitTcRgb) + buffer->mnFormat = GET_FORMAT; +#undef GET_FORMAT + break; + } + case 32: +#define GET_FORMAT \ + (kN32_SkColorType == kBGRA_8888_SkColorType ? ScanlineFormat::N32BitTcBgra \ + : ScanlineFormat::N32BitTcRgba) + buffer->mnFormat = GET_FORMAT; +#undef GET_FORMAT + break; + default: + abort(); + } + buffer->mnFormat |= ScanlineFormat::TopDown; +#ifdef DBG_UTIL + if (nMode == BitmapAccessMode::Write) + ++mWriteAccessCount; +#endif + return buffer; +} + +void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode) +{ + if (nMode == BitmapAccessMode::Write) + { +#ifdef DBG_UTIL + assert(mWriteAccessCount > 0); + --mWriteAccessCount; +#endif + mPalette = pBuffer->maPalette; + ResetCachedData(); + } + // Are there any more ground movements underneath us ? + assert(pBuffer->mnWidth == mSize.Width()); + assert(pBuffer->mnHeight == mSize.Height()); + assert(pBuffer->mnBitCount == mBitCount); + verify(); + delete pBuffer; +} + +bool SkiaSalBitmap::GetSystemData(BitmapSystemData&) +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + // TODO? + return false; +} + +bool SkiaSalBitmap::ScalingSupported() const { return true; } + +bool SkiaSalBitmap::Scale(const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag) +{ + SkiaZone zone; +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + Size newSize(FRound(mSize.Width() * rScaleX), FRound(mSize.Height() * rScaleY)); + if (mSize == newSize) + return true; + + SAL_INFO("vcl.skia.trace", "scale(" << this << "): " << mSize << "/" << mBitCount << "->" + << newSize << ":" << static_cast(nScaleFlag)); + + // The idea here is that the actual scaling will be delayed until the result + // is actually needed. Usually the scaled bitmap will be drawn somewhere, + // so delaying will mean the scaling can be done as a part of GetSkImage(). + // That means it can be GPU-accelerated, while done here directly it would need + // to be either done by CPU, or with the CPU->GPU->CPU roundtrip required + // by GPU-accelerated scaling. + // Pending scaling is detected by 'mSize != mPixelsSize'. + SkFilterQuality currentQuality; + switch (nScaleFlag) + { + case BmpScaleFlag::Fast: + currentQuality = kNone_SkFilterQuality; + break; + case BmpScaleFlag::Default: + currentQuality = kMedium_SkFilterQuality; + break; + case BmpScaleFlag::BestQuality: + currentQuality = kHigh_SkFilterQuality; + break; + default: + SAL_INFO("vcl.skia.trace", "scale(" << this << "): unsupported scale algorithm"); + return false; + } + if (mBitCount < 24 && !mPalette.IsGreyPalette8Bit()) + { + // Scaling can introduce additional colors not present in the original + // bitmap (e.g. when smoothing). If the bitmap is indexed (has non-trivial palette), + // this would break the bitmap, because the actual scaling is done only somewhen later. + // Linear 8bit palette (grey) is ok, since there we use directly the values as colors. + SAL_INFO("vcl.skia.trace", "scale(" << this << "): indexed bitmap"); + return false; + } + // if there is already one scale() pending, use the lowest quality of all requested + static_assert(kMedium_SkFilterQuality < kHigh_SkFilterQuality); + mScaleQuality = std::min(mScaleQuality, currentQuality); + // scaling will be actually done on-demand when needed, the need will be recognized + // by mSize != mPixelsSize + mSize = newSize; + // Do not reset cached data if mImage is possibly the only data we have. + if (mBuffer) + ResetCachedData(); + // The rest will be handled when the scaled bitmap is actually needed, + // such as in EnsureBitmapData() or GetSkImage(). + return true; +} + +bool SkiaSalBitmap::Replace(const Color&, const Color&, sal_uInt8) +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + // TODO? + return false; +} + +bool SkiaSalBitmap::ConvertToGreyscale() +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + // Normally this would need to convert contents of mBuffer for all possible formats, + // so just let the VCL algorithm do it. + // Avoid the costly SkImage->buffer->SkImage conversion. + if (!mBuffer && mImage) + { + if (mBitCount == 8 && mPalette.IsGreyPalette8Bit()) + return true; + sk_sp surface = SkiaHelper::createSkSurface(mPixelsSize); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + // VCL uses different coefficients for conversion to gray than Skia, so use the VCL + // values from Bitmap::ImplMakeGreyscales(). Do not use kGray_8_SkColorType, + // Skia would use its gray conversion formula. + // NOTE: The matrix is 4x5 organized as columns (i.e. each line is a column, not a row). + constexpr SkColorMatrix toGray(77 / 256.0, 151 / 256.0, 28 / 256.0, 0, 0, // R column + 77 / 256.0, 151 / 256.0, 28 / 256.0, 0, 0, // G column + 77 / 256.0, 151 / 256.0, 28 / 256.0, 0, 0, // B column + 0, 0, 0, 1, 0); // don't modify alpha + paint.setColorFilter(SkColorFilters::Matrix(toGray)); + surface->getCanvas()->drawImage(mImage, 0, 0, &paint); + mBitCount = 8; + mPalette = Bitmap::GetGreyPalette(256); + ResetToSkImage(SkiaHelper::makeCheckedImageSnapshot(surface)); + SAL_INFO("vcl.skia.trace", "converttogreyscale(" << this << ")"); + return true; + } + return false; +} + +bool SkiaSalBitmap::InterpretAs8Bit() +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + if (mBitCount == 8 && mPalette.IsGreyPalette8Bit()) + return true; + // This is usually used by AlphaMask, the point is just to treat + // the content as an alpha channel. This is often used + // by the horrible separate-alpha-outdev hack, where the bitmap comes + // from SkiaSalGraphicsImpl::GetBitmap(), so only mImage is set, + // and that is followed by a later call to GetAlphaSkImage(). + // Avoid the costly SkImage->buffer->SkImage conversion and simply + // just treat the SkImage as being for 8bit bitmap. EnsureBitmapData() + // will do the conversion if needed, but the normal case will be + // GetAlphaSkImage() creating kAlpha_8_SkColorType SkImage from it. + if (!mBuffer && mImage) + { + mBitCount = 8; + mPalette = Bitmap::GetGreyPalette(256); + ResetToSkImage(mImage); // keep mImage, it will be interpreted as 8bit if needed + SAL_INFO("vcl.skia.trace", "interpretas8bit(" << this << ")"); + return true; + } + return false; +} + +SkBitmap SkiaSalBitmap::GetAsSkBitmap() const +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + EnsureBitmapData(); + assert(mSize == mPixelsSize); // data has already been scaled if needed + SkiaZone zone; + SkBitmap bitmap; + if (mBuffer) + { + if (mBitCount == 32) + { + // Make a copy, the bitmap should be immutable (otherwise converting it + // to SkImage will make a copy anyway). + const size_t bytes = mPixelsSize.Height() * mScanlineSize; + std::unique_ptr data(new sal_uInt8[bytes]); + memcpy(data.get(), mBuffer.get(), bytes); +#if SKIA_USE_BITMAP32 + SkAlphaType alphaType = kPremul_SkAlphaType; +#else + SkAlphaType alphaType = kUnpremul_SkAlphaType; +#endif + if (!bitmap.installPixels( + SkImageInfo::MakeS32(mPixelsSize.Width(), mPixelsSize.Height(), alphaType), + data.release(), mPixelsSize.Width() * 4, + [](void* addr, void*) { delete[] static_cast(addr); }, nullptr)) + abort(); + bitmap.setImmutable(); + } + else if (mBitCount == 24) + { + // Convert 24bpp RGB/BGR to 32bpp RGBA/BGRA. + std::unique_ptr data( + new uint32_t[mPixelsSize.Height() * mPixelsSize.Width()]); + uint32_t* dest = data.get(); + for (long y = 0; y < mPixelsSize.Height(); ++y) + { + const sal_uInt8* src = mBuffer.get() + mScanlineSize * y; + // This also works as BGR to BGRA (the function extends 3 bytes to 4 + // by adding 0xFF alpha, so position of B and R doesn't matter). + SkExtendRGBToRGBA(dest, src, mPixelsSize.Width()); + dest += mPixelsSize.Width(); + } + if (!bitmap.installPixels( + SkImageInfo::MakeS32(mPixelsSize.Width(), mPixelsSize.Height(), + kOpaque_SkAlphaType), + data.release(), mPixelsSize.Width() * 4, + [](void* addr, void*) { delete[] static_cast(addr); }, nullptr)) + abort(); + bitmap.setImmutable(); + } + // Skia has a format for 8bit grayscale SkBitmap, but it seems to cause a problem + // with our PNG loader (tdf#121120), so convert it to RGBA below as well. + else + { +// Use a macro to hide an unreachable code warning. +#define GET_FORMAT \ + (kN32_SkColorType == kBGRA_8888_SkColorType ? BitConvert::BGRA : BitConvert::RGBA) + std::unique_ptr data + = convertDataBitCount(mBuffer.get(), mPixelsSize.Width(), mPixelsSize.Height(), + mBitCount, mScanlineSize, mPalette, GET_FORMAT); +#undef GET_FORMAT + if (!bitmap.installPixels( + SkImageInfo::MakeS32(mPixelsSize.Width(), mPixelsSize.Height(), + kOpaque_SkAlphaType), + data.release(), mPixelsSize.Width() * 4, + [](void* addr, void*) { delete[] static_cast(addr); }, nullptr)) + abort(); + bitmap.setImmutable(); + } + } + return bitmap; +} + +const sk_sp& SkiaSalBitmap::GetSkImage() const +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + if (mPixelsSize != mSize && !mImage + && SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster) + { + // The bitmap has a pending scaling, but no image. This function would below call GetAsSkBitmap(), + // which would do CPU-based pixel scaling, and then it would get converted to an image. + // Be more efficient, first convert to an image and then the block below will scale on the GPU. + SAL_INFO("vcl.skia.trace", "getskimage(" << this << "): shortcut image scaling " + << mPixelsSize << "->" << mSize); + SkiaSalBitmap* thisPtr = const_cast(this); + Size savedSize = mSize; + thisPtr->mSize = mPixelsSize; // block scaling + SkiaZone zone; + sk_sp image = SkiaHelper::createSkImage(GetAsSkBitmap()); + assert(image); + thisPtr->mSize = savedSize; + thisPtr->ResetToSkImage(image); + } + if (mImage) + { + if (mImage->width() != mSize.Width() || mImage->height() != mSize.Height()) + { + assert(!mBuffer); // This code should be only called if only mImage holds data. + SkiaZone zone; + sk_sp surface = SkiaHelper::createSkSurface(mSize); + assert(surface); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + paint.setFilterQuality(mScaleQuality); + surface->getCanvas()->drawImageRect( + mImage, SkRect::MakeWH(mImage->width(), mImage->height()), + SkRect::MakeWH(mSize.Width(), mSize.Height()), &paint); + SAL_INFO("vcl.skia.trace", "getskimage(" << this << "): image scaled " + << Size(mImage->width(), mImage->height()) + << "->" << mSize << ":" + << static_cast(mScaleQuality)); + SkiaSalBitmap* thisPtr = const_cast(this); + thisPtr->mImage = SkiaHelper::makeCheckedImageSnapshot(surface); + } + return mImage; + } + SkiaZone zone; + sk_sp image = SkiaHelper::createSkImage(GetAsSkBitmap()); + assert(image); + const_cast&>(mImage) = image; + SAL_INFO("vcl.skia.trace", "getskimage(" << this << ")"); + return mImage; +} + +const sk_sp& SkiaSalBitmap::GetAlphaSkImage() const +{ +#ifdef DBG_UTIL + assert(mWriteAccessCount == 0); +#endif + if (mAlphaImage) + { + assert(mSize == mPixelsSize); // data has already been scaled if needed + return mAlphaImage; + } + if (mImage) + { + SkiaZone zone; + sk_sp surface = SkiaHelper::createSkSurface(mSize, kAlpha_8_SkColorType); + assert(surface); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + // Move the R channel value to the alpha channel. This seems to be the only + // way to reinterpret data in SkImage as an alpha SkImage without accessing the pixels. + // NOTE: The matrix is 4x5 organized as columns (i.e. each line is a column, not a row). + constexpr SkColorMatrix redToAlpha(0, 0, 0, 0, 0, // R column + 0, 0, 0, 0, 0, // G column + 0, 0, 0, 0, 0, // B column + 1, 0, 0, 0, 0); // A column + paint.setColorFilter(SkColorFilters::Matrix(redToAlpha)); + bool scaling = mImage->width() != mSize.Width() || mImage->height() != mSize.Height(); + if (scaling) + { + assert(!mBuffer); // This code should be only called if only mImage holds data. + paint.setFilterQuality(mScaleQuality); + } + surface->getCanvas()->drawImageRect(mImage, + SkRect::MakeWH(mImage->width(), mImage->height()), + SkRect::MakeWH(mSize.Width(), mSize.Height()), &paint); + if (scaling) + SAL_INFO("vcl.skia.trace", "getalphaskimage(" << this << "): image scaled " + << Size(mImage->width(), mImage->height()) + << "->" << mSize << ":" + << static_cast(mScaleQuality)); + else + SAL_INFO("vcl.skia.trace", "getalphaskimage(" << this << ") from image"); + SkiaSalBitmap* thisPtr = const_cast(this); + thisPtr->mAlphaImage = SkiaHelper::makeCheckedImageSnapshot(surface); + return mAlphaImage; + } + SkiaZone zone; + EnsureBitmapData(); + assert(mSize == mPixelsSize); // data has already been scaled if needed + SkBitmap alphaBitmap; + if (mBuffer && mBitCount <= 8) + { + assert(mBuffer.get()); + verify(); + std::unique_ptr data + = convertDataBitCount(mBuffer.get(), mSize.Width(), mSize.Height(), mBitCount, + mScanlineSize, mPalette, BitConvert::A8); + if (!alphaBitmap.installPixels( + SkImageInfo::MakeA8(mSize.Width(), mSize.Height()), data.release(), mSize.Width(), + [](void* addr, void*) { delete[] static_cast(addr); }, nullptr)) + abort(); + alphaBitmap.setImmutable(); + sk_sp image = SkiaHelper::createSkImage(alphaBitmap); + assert(image); + const_cast&>(mAlphaImage) = image; + } + else + { + sk_sp surface = SkiaHelper::createSkSurface(mSize, kAlpha_8_SkColorType); + assert(surface); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + // Move the R channel value to the alpha channel. This seems to be the only + // way to reinterpret data in SkImage as an alpha SkImage without accessing the pixels. + // NOTE: The matrix is 4x5 organized as columns (i.e. each line is a column, not a row). + constexpr SkColorMatrix redToAlpha(0, 0, 0, 0, 0, // R column + 0, 0, 0, 0, 0, // G column + 0, 0, 0, 0, 0, // B column + 1, 0, 0, 0, 0); // A column + paint.setColorFilter(SkColorFilters::Matrix(redToAlpha)); + surface->getCanvas()->drawBitmap(GetAsSkBitmap(), 0, 0, &paint); + SkiaSalBitmap* thisPtr = const_cast(this); + thisPtr->mAlphaImage = SkiaHelper::makeCheckedImageSnapshot(surface); + } + SAL_INFO("vcl.skia.trace", "getalphaskimage(" << this << ")"); + return mAlphaImage; +} + +void SkiaSalBitmap::EnsureBitmapData() +{ + if (mBuffer) + { + if (mSize == mPixelsSize) + return; + // Pending scaling. Create raster SkImage from the bitmap data + // at the pixel size and then the code below will scale at the correct + // bpp from the image. + SAL_INFO("vcl.skia.trace", "ensurebitmapdata(" << this << "): pixels to be scaled " + << mPixelsSize << "->" << mSize << ":" + << static_cast(mScaleQuality)); + Size savedSize = mSize; + mSize = mPixelsSize; + ResetToSkImage(SkImage::MakeFromBitmap(GetAsSkBitmap())); + mSize = savedSize; + } + // Try to fill mBuffer from mImage. + if (!mImage) + return; + SkiaZone zone; + if (!CreateBitmapData()) + abort(); + SkAlphaType alphaType = kUnpremul_SkAlphaType; +#if SKIA_USE_BITMAP32 + if (mBitCount == 32) + alphaType = kPremul_SkAlphaType; +#endif + SkBitmap bitmap; + if (!bitmap.tryAllocPixels(SkImageInfo::MakeS32(mSize.Width(), mSize.Height(), alphaType))) + abort(); + SkCanvas canvas(bitmap); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + if (mSize != mPixelsSize) // pending scaling? + { + paint.setFilterQuality(mScaleQuality); + canvas.drawImageRect(mImage, + SkRect::MakeWH(mPixelsSize.getWidth(), mPixelsSize.getHeight()), + SkRect::MakeWH(mSize.getWidth(), mSize.getHeight()), &paint); + SAL_INFO("vcl.skia.trace", "ensurebitmapdata(" << this << "): image scaled " << mPixelsSize + << "->" << mSize << ":" + << static_cast(mScaleQuality)); + mPixelsSize = mSize; + mScaleQuality = kHigh_SkFilterQuality; + // Information about the pending scaling has been discarded, so make sure we do not + // keep around any cached images that would still need scaling. + ResetCachedDataBySize(); + } + else + canvas.drawImage(mImage, 0, 0, &paint); + canvas.flush(); + bitmap.setImmutable(); + assert(mBuffer != nullptr); + if (mBitCount == 32) + { + for (long y = 0; y < mSize.Height(); ++y) + { + const uint8_t* src = static_cast(bitmap.getAddr(0, y)); + sal_uInt8* dest = mBuffer.get() + mScanlineSize * y; + memcpy(dest, src, mScanlineSize); + } + } + else if (mBitCount == 24) // non-paletted + { + for (long y = 0; y < mSize.Height(); ++y) + { + const uint8_t* src = static_cast(bitmap.getAddr(0, y)); + sal_uInt8* dest = mBuffer.get() + mScanlineSize * y; + for (long x = 0; x < mSize.Width(); ++x) + { + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + ++src; // skip alpha + } + } + } + else if (mBitCount == 8 && mPalette.IsGreyPalette8Bit()) + { + for (long y = 0; y < mSize.Height(); ++y) + { + const uint8_t* src = static_cast(bitmap.getAddr(0, y)); + sal_uInt8* dest = mBuffer.get() + mScanlineSize * y; + // no actual data conversion, use one color channel as the gray value + for (long x = 0; x < mSize.Width(); ++x) + dest[x] = src[x * 4]; + } + } + else + { + std::unique_ptr pWriter + = vcl::ScanlineWriter::Create(mBitCount, mPalette); + for (long y = 0; y < mSize.Height(); ++y) + { + const uint8_t* src = static_cast(bitmap.getAddr(0, y)); + sal_uInt8* dest = mBuffer.get() + mScanlineSize * y; + pWriter->nextLine(dest); + for (long x = 0; x < mSize.Width(); ++x) + { + sal_uInt8 r = *src++; + sal_uInt8 g = *src++; + sal_uInt8 b = *src++; + ++src; // skip alpha + pWriter->writeRGB(r, g, b); + } + } + } + verify(); + SAL_INFO("vcl.skia.trace", "ensurebitmapdata(" << this << ")"); +} + +void SkiaSalBitmap::EnsureBitmapUniqueData() +{ + EnsureBitmapData(); + if (mBuffer.use_count() > 1) + { + sal_uInt32 allocate = mScanlineSize * mSize.Height(); +#ifdef DBG_UTIL + assert(memcmp(mBuffer.get() + allocate, CANARY, sizeof(CANARY)) == 0); + allocate += sizeof(CANARY); +#endif + boost::shared_ptr newBuffer = boost::make_shared_noinit(allocate); + memcpy(newBuffer.get(), mBuffer.get(), allocate); + mBuffer = newBuffer; + } +} + +void SkiaSalBitmap::ResetCachedData() +{ + SkiaZone zone; + // There may be a case when only mImage is set and CreatBitmapData() will create + // mBuffer from it if needed, in that case ResetToSkImage() should be used. + assert(mBuffer.get() || !mImage); + mImage.reset(); + mAlphaImage.reset(); +} + +void SkiaSalBitmap::ResetToSkImage(sk_sp image) +{ + SkiaZone zone; + mBuffer.reset(); + mImage = image; + mAlphaImage.reset(); +} + +void SkiaSalBitmap::ResetCachedDataBySize() +{ + SkiaZone zone; + assert(mSize == mPixelsSize); + if (mImage && (mImage->width() != mSize.getWidth() || mImage->height() != mSize.getHeight())) + mImage.reset(); + if (mAlphaImage + && (mAlphaImage->width() != mSize.getWidth() || mAlphaImage->height() != mSize.getHeight())) + mAlphaImage.reset(); +} + +#ifdef DBG_UTIL +void SkiaSalBitmap::dump(const char* file) const +{ + sk_sp saveImage = mImage; + sk_sp saveAlphaImage = mAlphaImage; + bool resetBuffer = !mBuffer; + int saveWriteAccessCount = mWriteAccessCount; + Size savePrescaleSize = mPixelsSize; + SkiaSalBitmap* thisPtr = const_cast(this); + // avoid possible assert + thisPtr->mWriteAccessCount = 0; + SkiaHelper::dump(GetSkImage(), file); + // restore old state, so that debugging doesn't affect it + if (resetBuffer) + thisPtr->mBuffer.reset(); + thisPtr->mImage = saveImage; + thisPtr->mAlphaImage = saveAlphaImage; + thisPtr->mWriteAccessCount = saveWriteAccessCount; + thisPtr->mPixelsSize = savePrescaleSize; +} + +void SkiaSalBitmap::verify() const +{ + if (!mBuffer) + return; + // Use mPixelsSize, that describes the size of the actual data. + assert(memcmp(mBuffer.get() + mScanlineSize * mPixelsSize.Height(), CANARY, sizeof(CANARY)) + == 0); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/skia_blacklist_vulkan.xml b/vcl/skia/skia_blacklist_vulkan.xml new file mode 100644 index 000000000..8a222d005 --- /dev/null +++ b/vcl/skia/skia_blacklist_vulkan.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx new file mode 100644 index 000000000..a4cbe062f --- /dev/null +++ b/vcl/skia/win/gdiimpl.cxx @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +WinSkiaSalGraphicsImpl::WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics, + SalGeometryProvider* mpProvider) + : SkiaSalGraphicsImpl(rGraphics, mpProvider) + , mWinParent(rGraphics) +{ +} + +void WinSkiaSalGraphicsImpl::createWindowContext(bool forceRaster) +{ + SkiaZone zone; + sk_app::DisplayParams displayParams; + switch (forceRaster ? SkiaHelper::RenderRaster : SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderRaster: + mWindowContext = sk_app::window_context_factory::MakeRasterForWin(mWinParent.gethWnd(), + displayParams); + break; + case SkiaHelper::RenderVulkan: + mWindowContext = sk_app::window_context_factory::MakeVulkanForWin(mWinParent.gethWnd(), + displayParams); + break; + } +} + +void WinSkiaSalGraphicsImpl::DeInit() +{ + SkiaZone zone; + SkiaSalGraphicsImpl::DeInit(); + mWindowContext.reset(); +} + +void WinSkiaSalGraphicsImpl::freeResources() {} + +void WinSkiaSalGraphicsImpl::performFlush() +{ + SkiaZone zone; + flushDrawing(); + if (mWindowContext) + mWindowContext->swapBuffers(); +} + +bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const& rControlCacheKey, + int nX, int nY) +{ + static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); + if (!gbCacheEnabled) + return false; + + auto& controlsCache = SkiaControlsCache::get(); + SkiaControlCacheType::const_iterator iterator = controlsCache.find(rControlCacheKey); + if (iterator == controlsCache.end()) + return false; + + preDraw(); + SAL_INFO("vcl.skia.trace", "tryrendercachednativecontrol(" + << this << "): " + << SkIRect::MakeXYWH(nX, nY, iterator->second->width(), + iterator->second->height())); + mSurface->getCanvas()->drawImage(iterator->second, nX, nY); + postDraw(); + return true; +} + +bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack, + int nX, int nY, + ControlCacheKey& aControlCacheKey) +{ + assert(dynamic_cast(&rWhite)); + assert(dynamic_cast(&rBlack)); + + sk_sp image = static_cast(rBlack).getAsImageDiff( + static_cast(rWhite)); + preDraw(); + SAL_INFO("vcl.skia.trace", + "renderandcachednativecontrol(" + << this << "): " << SkIRect::MakeXYWH(nX, nY, image->width(), image->height())); + mSurface->getCanvas()->drawImage(image, nX, nY); + postDraw(); + + if (!aControlCacheKey.canCacheControl()) + return true; + SkiaControlCachePair pair(aControlCacheKey, std::move(image)); + SkiaControlsCache::get().insert(std::move(pair)); + return true; +} + +#ifdef SAL_LOG_INFO +static HRESULT checkResult(HRESULT hr, const char* file, size_t line) +{ + if (FAILED(hr)) + { + OUString sLocationString + = OUString::createFromAscii(file) + ":" + OUString::number(line) + " "; + SAL_DETAIL_LOG_STREAM(SAL_DETAIL_ENABLE_LOG_INFO, ::SAL_DETAIL_LOG_LEVEL_INFO, "vcl.skia", + sLocationString.toUtf8().getStr(), + "HRESULT failed with: 0x" << OUString::number(hr, 16) << ": " + << WindowsErrorStringFromHRESULT(hr)); + } + return hr; +} + +#define CHECKHR(funct) checkResult(funct, __FILE__, __LINE__) +#else +#define CHECKHR(funct) (funct) +#endif + +sk_sp WinSkiaSalGraphicsImpl::createDirectWriteTypeface(const LOGFONTW& logFont) +{ + if (!dwriteDone) + { + if (SUCCEEDED( + CHECKHR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), + reinterpret_cast(&dwriteFactory))))) + { + if (SUCCEEDED(CHECKHR(dwriteFactory->GetGdiInterop(&dwriteGdiInterop)))) + dwriteFontMgr = SkFontMgr_New_DirectWrite(dwriteFactory); + else + dwriteFactory->Release(); + } + dwriteDone = true; + } + IDWriteFont* font = nullptr; + IDWriteFontFace* fontFace; + IDWriteFontFamily* fontFamily; + if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFromLOGFONT(&logFont, &font)))) + return nullptr; + if (FAILED(CHECKHR(font->CreateFontFace(&fontFace)))) + return nullptr; + if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily)))) + return nullptr; + return sk_sp( + SkCreateTypefaceDirectWrite(dwriteFontMgr, fontFace, font, fontFamily)); +} + +bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) +{ + const WinFontInstance& rWinFont = static_cast(rLayout.GetFont()); + float fHScale = rWinFont.getHScale(); + + assert(dynamic_cast(&rLayout.GetFont())); + const WinFontInstance* pWinFont = static_cast(&rLayout.GetFont()); + const HFONT hLayoutFont = pWinFont->GetHFONT(); + LOGFONTW logFont; + if (GetObjectW(hLayoutFont, sizeof(logFont), &logFont) == 0) + { + assert(false); + return false; + } + sk_sp typeface = createDirectWriteTypeface(logFont); + GlyphOrientation glyphOrientation = GlyphOrientation::Apply; + if (!typeface) // fall back to GDI text rendering + { + typeface.reset(SkCreateTypefaceFromLOGFONT(logFont)); + glyphOrientation = GlyphOrientation::Ignore; + } + // lfHeight actually depends on DPI, so it's not really font height as such, + // but for LOGFONT-based typefaces Skia simply sets lfHeight back to this value + // directly. + double fontHeight = logFont.lfHeight; + if (fontHeight < 0) + fontHeight = -fontHeight; + SkFont font(typeface, fontHeight, fHScale, 0); + font.setEdging(getFontEdging()); + assert(dynamic_cast(mWinParent.GetImpl())); + SkiaSalGraphicsImpl* impl = static_cast(mWinParent.GetImpl()); + COLORREF color = ::GetTextColor(mWinParent.getHDC()); + Color salColor(GetRValue(color), GetGValue(color), GetBValue(color)); + // The font already is set up to have glyphs rotated as needed. + impl->drawGenericLayout(rLayout, salColor, font, glyphOrientation); + return true; +} + +SkFont::Edging WinSkiaSalGraphicsImpl::getFontEdging() +{ + if (fontEdgingDone) + return fontEdging; + // Skia needs to be explicitly told what kind of antialiasing should be used, + // get it from system settings. This does not actually matter for the text + // rendering itself, since Skia has been patched to simply use the setting + // from the LOGFONT, which gets set by VCL's ImplGetLogFontFromFontSelect() + // and that one normally uses DEFAULT_QUALITY, so Windows will select + // the appropriate AA setting. But Skia internally chooses the format to which + // the glyphs will be rendered based on this setting (subpixel AA requires colors, + // others do not). + fontEdging = SkFont::Edging::kAlias; + SkFontLCDConfig::LCDOrder lcdOrder = SkFontLCDConfig::kNONE_LCDOrder; + BOOL set; + if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &set, 0) && set) + { + UINT set2; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &set2, 0) + && set2 == FE_FONTSMOOTHINGCLEARTYPE) + { + fontEdging = SkFont::Edging::kSubpixelAntiAlias; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &set2, 0) + && set2 == FE_FONTSMOOTHINGORIENTATIONBGR) + lcdOrder = SkFontLCDConfig::kBGR_LCDOrder; + else + lcdOrder = SkFontLCDConfig::kRGB_LCDOrder; // default + } + else + fontEdging = SkFont::Edging::kAntiAlias; + } + SkFontLCDConfig::SetSubpixelOrder(lcdOrder); + // Cache this, it is actually visible a little bit when profiling. + fontEdgingDone = true; + return fontEdging; +} + +void WinSkiaSalGraphicsImpl::ClearDevFontCache() +{ + dwriteFontMgr.reset(); + dwriteDone = false; + fontEdgingDone = false; +} + +SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height) + : CompatibleDC(rGraphics, x, y, width, height, false) +{ +} + +std::unique_ptr SkiaCompatibleDC::getAsMaskTexture() const +{ + auto ret = std::make_unique(); + ret->image = getAsMaskImage(); + return ret; +} + +sk_sp SkiaCompatibleDC::getAsMaskImage() const +{ + SkiaZone zone; + // mpData is in the BGRA format, with A unused (and set to 0), and RGB are grey, + // so convert it to Skia format, then to 8bit and finally use as alpha mask + SkBitmap tmpBitmap; + if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, + kBGRA_8888_SkColorType, kOpaque_SkAlphaType), + mpData, maRects.mnSrcWidth * 4)) + abort(); + tmpBitmap.setImmutable(); + SkBitmap bitmap8; + if (!bitmap8.tryAllocPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, + kGray_8_SkColorType, kOpaque_SkAlphaType))) + abort(); + SkCanvas canvas8(bitmap8); + SkPaint paint8; + paint8.setBlendMode(SkBlendMode::kSrc); // copy and convert depth + // The data we got is upside-down. + SkMatrix matrix; + matrix.preTranslate(0, maRects.mnSrcHeight); + matrix.setConcat(matrix, SkMatrix::Scale(1, -1)); + canvas8.concat(matrix); + canvas8.drawBitmap(tmpBitmap, 0, 0, &paint8); + bitmap8.setImmutable(); + // use the 8bit data as an alpha channel + SkBitmap alpha; + alpha.setInfo(bitmap8.info().makeColorType(kAlpha_8_SkColorType), bitmap8.rowBytes()); + alpha.setPixelRef(sk_ref_sp(bitmap8.pixelRef()), bitmap8.pixelRefOrigin().x(), + bitmap8.pixelRefOrigin().y()); + alpha.setImmutable(); + return SkiaHelper::createSkImage(alpha); +} + +sk_sp SkiaCompatibleDC::getAsImage() const +{ + SkiaZone zone; + SkBitmap tmpBitmap; + if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, + kBGRA_8888_SkColorType, kUnpremul_SkAlphaType), + mpData, maRects.mnSrcWidth * 4)) + abort(); + tmpBitmap.setImmutable(); + sk_sp surface = SkiaHelper::createSkSurface(tmpBitmap.width(), tmpBitmap.height()); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + SkCanvas* canvas = surface->getCanvas(); + canvas->save(); + // The data we got is upside-down. + SkMatrix matrix; + matrix.preTranslate(0, maRects.mnSrcHeight); + matrix.setConcat(matrix, SkMatrix::Scale(1, -1)); + canvas->concat(matrix); + canvas->drawBitmapRect(tmpBitmap, + SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), + SkRect::MakeXYWH(0, 0, maRects.mnSrcWidth, maRects.mnSrcHeight), &paint); + canvas->restore(); + return SkiaHelper::makeCheckedImageSnapshot(surface); +} + +sk_sp SkiaCompatibleDC::getAsImageDiff(const SkiaCompatibleDC& white) const +{ + SkiaZone zone; + assert(maRects.mnSrcWidth == white.maRects.mnSrcWidth + || maRects.mnSrcHeight == white.maRects.mnSrcHeight); + SkBitmap tmpBitmap; + if (!tmpBitmap.tryAllocPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, + kBGRA_8888_SkColorType, kPremul_SkAlphaType), + maRects.mnSrcWidth * 4)) + abort(); + // Native widgets are drawn twice on black/white background to synthetize alpha + // (commit c6b66646870cb2bffaa73565affcf80bf74e0b5c). The problem is that + // most widgets when drawn on transparent background are drawn properly (and the result + // is in premultiplied alpha format), some such as "Edit" (used by ControlType::Editbox) + // keep the alpha channel as transparent. Therefore the alpha is actually computed + // from the difference in the premultiplied red channels when drawn one black and on white. + // Alpha is computed as "alpha = 1.0 - abs(black.red - white.red)". + // TODO I doubt this can be done using Skia, so do it manually here. Fortunately + // the bitmaps should be fairly small and are cached. + uint32_t* dest = tmpBitmap.getAddr32(0, 0); + assert(dest == tmpBitmap.getPixels()); + const sal_uInt32* src = mpData; + const sal_uInt32* whiteSrc = white.mpData; + uint32_t* end = dest + tmpBitmap.width() * tmpBitmap.height(); + while (dest < end) + { + uint32_t alpha = 255 - abs(int(*src & 0xff) - int(*whiteSrc & 0xff)); + *dest = (*src & 0x00ffffff) | (alpha << 24); + ++dest; + ++src; + ++whiteSrc; + } + tmpBitmap.notifyPixelsChanged(); + tmpBitmap.setImmutable(); + sk_sp surface = SkiaHelper::createSkSurface(tmpBitmap.width(), tmpBitmap.height()); + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + SkCanvas* canvas = surface->getCanvas(); + canvas->save(); + // The data we got is upside-down. + SkMatrix matrix; + matrix.preTranslate(0, tmpBitmap.height()); + matrix.setConcat(matrix, SkMatrix::Scale(1, -1)); + canvas->concat(matrix); + canvas->drawBitmap(tmpBitmap, 0, 0, &paint); + canvas->restore(); + return SkiaHelper::makeCheckedImageSnapshot(surface); +} + +SkiaControlsCache::SkiaControlsCache() + : cache(200) +{ +} + +SkiaControlCacheType& SkiaControlsCache::get() +{ + SalData* data = GetSalData(); + if (!data->m_pSkiaControlsCache) + data->m_pSkiaControlsCache.reset(new SkiaControlsCache); + return data->m_pSkiaControlsCache->cache; +} + +namespace +{ +std::unique_ptr createVulkanWindowContext(bool /*temporary*/) +{ + SkiaZone zone; + sk_app::DisplayParams displayParams; + return sk_app::window_context_factory::MakeVulkanForWin(nullptr, displayParams); +} +} + +void WinSkiaSalGraphicsImpl::prepareSkia() { SkiaHelper::prepareSkia(createVulkanWindowContext); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx new file mode 100644 index 000000000..1602218c1 --- /dev/null +++ b/vcl/skia/x11/gdiimpl.cxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Some of this code is based on Skia source code, covered by the following + * license notice (see readlicense_oo for the full license): + * + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + */ + +#include + +#include + +#include +#include + +#include + +X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent) + : SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider()) + , mX11Parent(rParent) +{ +} + +X11SkiaSalGraphicsImpl::~X11SkiaSalGraphicsImpl() {} + +void X11SkiaSalGraphicsImpl::Init() +{ + // The m_pFrame and m_pVDev pointers are updated late in X11 + setProvider(mX11Parent.GetGeometryProvider()); + SkiaSalGraphicsImpl::Init(); +} + +void X11SkiaSalGraphicsImpl::createWindowContext(bool forceRaster) +{ + assert(mX11Parent.GetDrawable() != None); + mWindowContext = createWindowContext( + mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), &mX11Parent.GetVisual(), GetWidth(), + GetHeight(), forceRaster ? SkiaHelper::RenderRaster : SkiaHelper::renderMethodToUse(), + false); +} + +std::unique_ptr +X11SkiaSalGraphicsImpl::createWindowContext(Display* display, Drawable drawable, + const XVisualInfo* visual, int width, int height, + SkiaHelper::RenderMethod renderMethod, bool temporary) +{ + SkiaZone zone; + sk_app::DisplayParams displayParams; + displayParams.fColorType = kN32_SkColorType; + sk_app::window_context_factory::XlibWindowInfo winInfo; + assert(display); + winInfo.fDisplay = display; + winInfo.fWindow = drawable; + winInfo.fFBConfig = nullptr; // not used + winInfo.fVisualInfo = const_cast(visual); + assert(winInfo.fVisualInfo->visual != nullptr); // make sure it's not an uninitialized SalVisual + winInfo.fWidth = width; + winInfo.fHeight = height; +#ifdef DBG_UTIL + // Our patched Skia has VulkanWindowContext that shares GrContext, which requires + // that the X11 visual is always the same. Ensure it is so. + static VisualID checkVisualID = -1U; + // Exception is for the temporary case during startup, when SkiaHelper's + // checkDeviceBlacklisted() needs a WindowContext and may be called before SalVisual + // is ready. + if (!temporary) + { + assert(checkVisualID == -1U || winInfo.fVisualInfo->visualid == checkVisualID); + checkVisualID = winInfo.fVisualInfo->visualid; + } +#else + (void)temporary; +#endif + switch (renderMethod) + { + case SkiaHelper::RenderRaster: + // TODO The Skia Xlib code actually requires the non-native color type to work properly. + displayParams.fColorType + = (displayParams.fColorType == kBGRA_8888_SkColorType ? kRGBA_8888_SkColorType + : kBGRA_8888_SkColorType); + return sk_app::window_context_factory::MakeRasterForXlib(winInfo, displayParams); + case SkiaHelper::RenderVulkan: + return sk_app::window_context_factory::MakeVulkanForXlib(winInfo, displayParams); + } + abort(); +} + +bool X11SkiaSalGraphicsImpl::avoidRecreateByResize() const +{ + if (!mSurface || isOffscreen()) + return false; + // Skia's WindowContext uses actual dimensions of the X window, which due to X11 being + // asynchronous may be temporarily different from what VCL thinks are the dimensions. + // That can lead to us repeatedly calling recreateSurface() because of "incorrect" + // size, and we otherwise need to check for size changes, because VCL does not inform us. + // Avoid the problem here by checking the size of the X window and bail out if Skia + // would just return the same size as it is now. + Window r; + int x, y; + unsigned int w, h, border, depth; + XGetGeometry(mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), &r, &x, &y, &w, &h, &border, + &depth); + return mSurface->width() == int(w) && mSurface->height() == int(h); +} + +void X11SkiaSalGraphicsImpl::DeInit() +{ + SkiaZone zone; + SkiaSalGraphicsImpl::DeInit(); + mWindowContext.reset(); +} + +void X11SkiaSalGraphicsImpl::freeResources() {} + +void X11SkiaSalGraphicsImpl::performFlush() +{ + SkiaZone zone; + flushDrawing(); + // TODO XPutImage() is somewhat inefficient, XShmPutImage() should be preferred. + mWindowContext->swapBuffers(); +} + +std::unique_ptr createVulkanWindowContext(bool temporary) +{ + SalDisplay* salDisplay = vcl_sal::getSalDisplay(GetGenericUnixSalData()); + const XVisualInfo* visual; + XVisualInfo* visuals = nullptr; + if (!temporary) + visual = &salDisplay->GetVisual(salDisplay->GetDefaultXScreen()); + else + { + // SalVisual from salDisplay may not be setup yet at this point, get + // info for the default visual. + XVisualInfo search; + search.visualid = XVisualIDFromVisual( + DefaultVisual(salDisplay->GetDisplay(), salDisplay->GetDefaultXScreen().getXScreen())); + int count; + visuals = XGetVisualInfo(salDisplay->GetDisplay(), VisualIDMask, &search, &count); + assert(count == 1); + visual = visuals; + } + std::unique_ptr ret = X11SkiaSalGraphicsImpl::createWindowContext( + salDisplay->GetDisplay(), None, visual, 1, 1, SkiaHelper::RenderVulkan, temporary); + if (temporary) + XFree(visuals); + return ret; +} + +void X11SkiaSalGraphicsImpl::prepareSkia() { SkiaHelper::prepareSkia(createVulkanWindowContext); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/x11/salvd.cxx b/vcl/skia/x11/salvd.cxx new file mode 100644 index 000000000..a4db9c75d --- /dev/null +++ b/vcl/skia/x11/salvd.cxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include +#include + +#include + +void X11SalGraphics::Init(X11SkiaSalVirtualDevice* pDevice) +{ + SalDisplay* pDisplay = pDevice->GetDisplay(); + + m_nXScreen = pDevice->GetXScreenNumber(); + m_pColormap = &pDisplay->GetColormap(m_nXScreen); + + m_pVDev = pDevice; + m_pFrame = nullptr; + + bWindow_ = pDisplay->IsDisplay(); + bVirDev_ = true; + + mxImpl->Init(); +} + +X11SkiaSalVirtualDevice::X11SkiaSalVirtualDevice(SalGraphics const* pGraphics, long nDX, long nDY, + const SystemGraphicsData* pData, + std::unique_ptr pNewGraphics) + : mpGraphics(std::move(pNewGraphics)) + , mbGraphics(false) + , mnXScreen(0) +{ + assert(mpGraphics); + + // TODO Check where a VirtualDevice is created from SystemGraphicsData + assert(pData == nullptr); + (void)pData; + + mpDisplay = vcl_sal::getSalDisplay(GetGenericUnixSalData()); + mnXScreen = pGraphics ? static_cast(pGraphics)->GetScreenNumber() + : vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDefaultXScreen(); + mnWidth = nDX; + mnHeight = nDY; + mpGraphics->Init(this); +} + +X11SkiaSalVirtualDevice::~X11SkiaSalVirtualDevice() {} + +SalGraphics* X11SkiaSalVirtualDevice::AcquireGraphics() +{ + if (mbGraphics) + return nullptr; + + if (mpGraphics) + mbGraphics = true; + + return mpGraphics.get(); +} + +void X11SkiaSalVirtualDevice::ReleaseGraphics(SalGraphics*) { mbGraphics = false; } + +bool X11SkiaSalVirtualDevice::SetSize(long nDX, long nDY) +{ + if (!nDX) + nDX = 1; + if (!nDY) + nDY = 1; + + mnWidth = nDX; + mnHeight = nDY; + if (mpGraphics) + mpGraphics->Init(this); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/x11/textrender.cxx b/vcl/skia/x11/textrender.cxx new file mode 100644 index 000000000..13eff3012 --- /dev/null +++ b/vcl/skia/x11/textrender.cxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGraphics& rGraphics) +{ + const FreetypeFontInstance& rInstance = static_cast(rLayout.GetFont()); + const FreetypeFont& rFont = rInstance.GetFreetypeFont(); + const FontSelectPattern& rFSD = rInstance.GetFontSelectPattern(); + int nHeight = rFSD.mnHeight; + int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; + if (nWidth == 0 || nHeight == 0) + return; + + if (FreetypeFont::AlmostHorizontalDrainsRenderingPool(nWidth * 10 / nHeight, rFSD)) + return; + + if (!fontManager) + { + // Get the global FcConfig that our VCL fontconfig code uses, and refcount it. + fontManager = SkFontMgr_New_FontConfig(FcConfigReference(nullptr)); + } + sk_sp typeface + = SkFontMgr_createTypefaceFromFcPattern(fontManager, rFont.GetFontOptions()->GetPattern()); + SkFont font(typeface, nHeight); + // TODO are these correct? + if (rFont.NeedsArtificialItalic()) + font.setSkewX(-0x6000L / 0x10000L); + if (rFont.NeedsArtificialBold()) + font.setEmbolden(true); + font.setEdging(rFont.GetAntialiasAdvice() ? SkFont::Edging::kAntiAlias + : SkFont::Edging::kAlias); + + assert(dynamic_cast(rGraphics.GetImpl())); + SkiaSalGraphicsImpl* impl = static_cast(rGraphics.GetImpl()); + impl->drawGenericLayout(rLayout, mnTextColor, font, + SkiaSalGraphicsImpl::GlyphOrientation::Apply); +} + +void SkiaTextRender::ClearDevFontCache() { fontManager.reset(); } + +#if 0 +// SKIA TODO +void FontConfigFontOptions::cairo_font_options_substitute(FcPattern* pPattern) +{ + ImplSVData* pSVData = ImplGetSVData(); + const cairo_font_options_t* pFontOptions = pSVData->mpDefInst->GetCairoFontOptions(); + if( !pFontOptions ) + return; + cairo_ft_font_options_substitute(pFontOptions, pPattern); +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/skia/zone.cxx b/vcl/skia/zone.cxx new file mode 100644 index 000000000..50f5e1ea7 --- /dev/null +++ b/vcl/skia/zone.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include +#include +#include + +#include +#include + +#include + +/** + * Called from a signal handler or watchdog thread if we get + * a crash or hang in some driver. + */ +void SkiaZone::hardDisable() +{ + // protect ourselves from double calling etc. + static bool bDisabled = false; + if (!bDisabled) + { + bDisabled = true; + + // Instead of disabling Skia as a whole, only force the CPU-based + // raster mode, which should be safe as it does not use drivers. + std::shared_ptr xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::VCL::ForceSkiaRaster::set(true, xChanges); + xChanges->commit(); + + // Force synchronous config write + css::uno::Reference( + css::configuration::theDefaultProvider::get(comphelper::getProcessComponentContext()), + css::uno::UNO_QUERY_THROW) + ->flush(); + } +} + +void SkiaZone::checkDebug(int nUnchanged, const CrashWatchdogTimingsValues& aTimingValues) +{ + SAL_INFO("vcl.watchdog", "Skia watchdog - unchanged " + << nUnchanged << " enter count " << enterCount() + << " breakpoints mid: " << aTimingValues.mnDisableEntries + << " max " << aTimingValues.mnAbortAfter); +} + +const CrashWatchdogTimingsValues& SkiaZone::getCrashWatchdogTimingsValues() +{ + switch (SkiaHelper::renderMethodToUse()) + { + case SkiaHelper::RenderVulkan: + { + static const CrashWatchdogTimingsValues vulkanValues = { 6, 20 }; /* 1.5s, 5s */ + return vulkanValues; + } + case SkiaHelper::RenderRaster: + { + // CPU-based operations with large images may take a noticeably long time, + // so use large values. CPU-based rendering shouldn't use any unstable drivers anyway. + static const CrashWatchdogTimingsValues rasterValues = { 600, 2000 }; /* 150s, 500s */ + return rasterValues; + } + } + O3TL_UNREACHABLE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/animate/Animation.cxx b/vcl/source/animate/Animation.cxx new file mode 100644 index 000000000..d9eaed56c --- /dev/null +++ b/vcl/source/animate/Animation.cxx @@ -0,0 +1,678 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +sal_uLong Animation::mnAnimCount = 0; + +Animation::Animation() + : mnLoopCount(0) + , mnLoops(0) + , mnPos(0) + , mbIsInAnimation(false) + , mbLoopTerminated(false) +{ + maTimer.SetInvokeHandler(LINK(this, Animation, ImplTimeoutHdl)); +} + +Animation::Animation(const Animation& rAnimation) + : maBitmapEx(rAnimation.maBitmapEx) + , maGlobalSize(rAnimation.maGlobalSize) + , mnLoopCount(rAnimation.mnLoopCount) + , mnPos(rAnimation.mnPos) + , mbIsInAnimation(false) + , mbLoopTerminated(rAnimation.mbLoopTerminated) +{ + for (auto const& i : rAnimation.maList) + maList.emplace_back(new AnimationBitmap(*i)); + + maTimer.SetInvokeHandler(LINK(this, Animation, ImplTimeoutHdl)); + mnLoops = mbLoopTerminated ? 0 : mnLoopCount; +} + +Animation::~Animation() +{ + if (mbIsInAnimation) + Stop(); +} + +Animation& Animation::operator=(const Animation& rAnimation) +{ + if (this != &rAnimation) + { + Clear(); + + for (auto const& i : rAnimation.maList) + maList.emplace_back(new AnimationBitmap(*i)); + + maGlobalSize = rAnimation.maGlobalSize; + maBitmapEx = rAnimation.maBitmapEx; + mnLoopCount = rAnimation.mnLoopCount; + mnPos = rAnimation.mnPos; + mbLoopTerminated = rAnimation.mbLoopTerminated; + mnLoops = mbLoopTerminated ? 0 : mnLoopCount; + } + return *this; +} + +bool Animation::operator==(const Animation& rAnimation) const +{ + return maList.size() == rAnimation.maList.size() && maBitmapEx == rAnimation.maBitmapEx + && maGlobalSize == rAnimation.maGlobalSize + && std::equal(maList.begin(), maList.end(), rAnimation.maList.begin(), + [](const std::unique_ptr& pAnim1, + const std::unique_ptr& pAnim2) -> bool { + return *pAnim1 == *pAnim2; + }); +} + +void Animation::Clear() +{ + maTimer.Stop(); + mbIsInAnimation = false; + maGlobalSize = Size(); + maBitmapEx.SetEmpty(); + maList.clear(); + maViewList.clear(); +} + +bool Animation::IsTransparent() const +{ + tools::Rectangle aRect{ Point(), maGlobalSize }; + + // If some small bitmap needs to be replaced by the background, + // we need to be transparent, in order to be displayed correctly + // as the application (?) does not invalidate on non-transparent + // graphics due to performance reasons. + + return maBitmapEx.IsTransparent() + || std::any_of(maList.begin(), maList.end(), + [&aRect](const std::unique_ptr& pAnim) -> bool { + return pAnim->meDisposal == Disposal::Back + && tools::Rectangle{ pAnim->maPositionPixel, + pAnim->maSizePixel } + != aRect; + }); +} + +sal_uLong Animation::GetSizeBytes() const +{ + sal_uLong nSizeBytes = GetBitmapEx().GetSizeBytes(); + + for (auto const& pAnimationBitmap : maList) + { + nSizeBytes += pAnimationBitmap->maBitmapEx.GetSizeBytes(); + } + + return nSizeBytes; +} + +BitmapChecksum Animation::GetChecksum() const +{ + SVBT32 aBT32; + BitmapChecksumOctetArray aBCOA; + BitmapChecksum nCrc = GetBitmapEx().GetChecksum(); + + UInt32ToSVBT32(maList.size(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(maGlobalSize.Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(maGlobalSize.Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + for (auto const& i : maList) + { + BCToBCOA(i->GetChecksum(), aBCOA); + nCrc = vcl_get_checksum(nCrc, aBCOA, BITMAP_CHECKSUM_SIZE); + } + + return nCrc; +} + +bool Animation::Start(OutputDevice* pOut, const Point& rDestPt, const Size& rDestSz, + long nExtraData, OutputDevice* pFirstFrameOutDev) +{ + bool bRet = false; + + if (!maList.empty()) + { + if ((pOut->GetOutDevType() == OUTDEV_WINDOW) && !mbLoopTerminated + && (ANIMATION_TIMEOUT_ON_CLICK != maList[mnPos]->mnWait)) + { + bool differs = true; + + auto itAnimView = std::find_if( + maViewList.begin(), maViewList.end(), + [pOut, nExtraData](const std::unique_ptr& pAnimView) -> bool { + return pAnimView->matches(pOut, nExtraData); + }); + + if (itAnimView != maViewList.end()) + { + if ((*itAnimView)->getOutPos() == rDestPt + && (*itAnimView)->getOutSizePix() == pOut->LogicToPixel(rDestSz)) + { + (*itAnimView)->repaint(); + differs = false; + } + else + maViewList.erase(itAnimView); + } + + if (maViewList.empty()) + { + maTimer.Stop(); + mbIsInAnimation = false; + mnPos = 0; + } + + if (differs) + maViewList.emplace_back( + new ImplAnimView(this, pOut, rDestPt, rDestSz, nExtraData, pFirstFrameOutDev)); + + if (!mbIsInAnimation) + { + ImplRestartTimer(maList[mnPos]->mnWait); + mbIsInAnimation = true; + } + } + else + Draw(pOut, rDestPt, rDestSz); + + bRet = true; + } + + return bRet; +} + +void Animation::Stop(OutputDevice* pOut, long nExtraData) +{ + maViewList.erase(std::remove_if(maViewList.begin(), maViewList.end(), + [=](const std::unique_ptr& pAnimView) -> bool { + return pAnimView->matches(pOut, nExtraData); + }), + maViewList.end()); + + if (maViewList.empty()) + { + 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 size_t nCount = maList.size(); + + if (nCount) + { + AnimationBitmap* pObj = maList[std::min(mnPos, nCount - 1)].get(); + + if (pOut->GetConnectMetaFile() || (pOut->GetOutDevType() == OUTDEV_PRINTER)) + maList[0]->maBitmapEx.Draw(pOut, rDestPt, rDestSz); + else if (ANIMATION_TIMEOUT_ON_CLICK == pObj->mnWait) + pObj->maBitmapEx.Draw(pOut, rDestPt, rDestSz); + else + { + const size_t nOldPos = mnPos; + if (mbLoopTerminated) + const_cast(this)->mnPos = nCount - 1; + + { + ImplAnimView{ const_cast(this), pOut, rDestPt, rDestSz, 0 }; + } + + const_cast(this)->mnPos = nOldPos; + } + } +} + +namespace +{ +constexpr sal_uLong constMinTimeout = 2; +} + +void Animation::ImplRestartTimer(sal_uLong nTimeout) +{ + maTimer.SetTimeout(std::max(nTimeout, constMinTimeout) * 10); + maTimer.Start(); +} + +IMPL_LINK_NOARG(Animation, ImplTimeoutHdl, Timer*, void) +{ + const size_t nAnimCount = maList.size(); + + if (nAnimCount) + { + bool bGlobalPause = false; + + if (maNotifyLink.IsSet()) + { + std::vector> aAInfoList; + // create AInfo-List + for (auto const& i : maViewList) + aAInfoList.emplace_back(i->createAInfo()); + + maNotifyLink.Call(this); + + // set view state from AInfo structure + for (auto& pAInfo : aAInfoList) + { + ImplAnimView* pView = nullptr; + if (!pAInfo->pViewData) + { + pView = new ImplAnimView(this, pAInfo->pOutDev, pAInfo->aStartOrg, + pAInfo->aStartSize, pAInfo->nExtraData); + + maViewList.push_back(std::unique_ptr(pView)); + } + else + pView = static_cast(pAInfo->pViewData); + + pView->pause(pAInfo->bPause); + pView->setMarked(true); + } + + // delete all unmarked views + auto removeStart = std::remove_if(maViewList.begin(), maViewList.end(), + [](const auto& pView) { return !pView->isMarked(); }); + maViewList.erase(removeStart, maViewList.cend()); + + // check if every remaining view is paused + bGlobalPause = std::all_of(maViewList.cbegin(), maViewList.cend(), + [](const auto& pView) { return pView->isPause(); }); + + // reset marked state + std::for_each(maViewList.cbegin(), maViewList.cend(), + [](const auto& pView) { pView->setMarked(false); }); + } + + if (maViewList.empty()) + Stop(); + else if (bGlobalPause) + ImplRestartTimer(10); + else + { + AnimationBitmap* pStepBmp = (++mnPos < maList.size()) ? maList[mnPos].get() : nullptr; + + if (!pStepBmp) + { + if (mnLoops == 1) + { + Stop(); + mbLoopTerminated = true; + mnPos = nAnimCount - 1; + maBitmapEx = maList[mnPos]->maBitmapEx; + return; + } + else + { + if (mnLoops) + mnLoops--; + + mnPos = 0; + pStepBmp = maList[mnPos].get(); + } + } + + // Paint all views. + std::for_each(maViewList.cbegin(), maViewList.cend(), + [this](const auto& pView) { pView->draw(mnPos); }); + /* + * If a view is marked, remove the view, because + * area of output lies out of display area of window. + * Mark state is set from view itself. + */ + auto removeStart = std::remove_if(maViewList.begin(), maViewList.end(), + [](const auto& pView) { return pView->isMarked(); }); + maViewList.erase(removeStart, maViewList.cend()); + + // stop or restart timer + if (maViewList.empty()) + Stop(); + else + ImplRestartTimer(pStepBmp->mnWait); + } + } + else + Stop(); +} + +bool Animation::Insert(const AnimationBitmap& rStepBmp) +{ + bool bRet = false; + + if (!IsInAnimation()) + { + tools::Rectangle aGlobalRect(Point(), maGlobalSize); + + maGlobalSize + = aGlobalRect.Union(tools::Rectangle(rStepBmp.maPositionPixel, rStepBmp.maSizePixel)) + .GetSize(); + maList.emplace_back(new AnimationBitmap(rStepBmp)); + + // As a start, we make the first BitmapEx the replacement BitmapEx + if (maList.size() == 1) + maBitmapEx = rStepBmp.maBitmapEx; + + bRet = true; + } + + return bRet; +} + +const AnimationBitmap& Animation::Get(sal_uInt16 nAnimation) const +{ + SAL_WARN_IF((nAnimation >= maList.size()), "vcl", "No object at this position"); + return *maList[nAnimation]; +} + +void Animation::Replace(const AnimationBitmap& rNewAnimationBitmap, sal_uInt16 nAnimation) +{ + SAL_WARN_IF((nAnimation >= maList.size()), "vcl", "No object at this position"); + + maList[nAnimation].reset(new AnimationBitmap(rNewAnimationBitmap)); + + // If we insert at first position we also need to + // update the replacement BitmapEx + if ((!nAnimation && (!mbLoopTerminated || (maList.size() == 1))) + || ((nAnimation == maList.size() - 1) && mbLoopTerminated)) + { + maBitmapEx = rNewAnimationBitmap.maBitmapEx; + } +} + +void Animation::SetLoopCount(const sal_uInt32 nLoopCount) +{ + mnLoopCount = nLoopCount; + ResetLoopCount(); +} + +void Animation::ResetLoopCount() +{ + mnLoops = mnLoopCount; + mbLoopTerminated = false; +} + +void Animation::Convert(BmpConversion eConversion) +{ + SAL_WARN_IF(IsInAnimation(), "vcl", "Animation modified while it is animated"); + + bool bRet; + + if (!IsInAnimation() && !maList.empty()) + { + bRet = true; + + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + bRet = maList[i]->maBitmapEx.Convert(eConversion); + + maBitmapEx.Convert(eConversion); + } +} + +bool Animation::ReduceColors(sal_uInt16 nNewColorCount) +{ + SAL_WARN_IF(IsInAnimation(), "vcl", "Animation modified while it is animated"); + + bool bRet; + + if (!IsInAnimation() && !maList.empty()) + { + bRet = true; + + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + { + bRet = BitmapFilter::Filter(maList[i]->maBitmapEx, + BitmapColorQuantizationFilter(nNewColorCount)); + } + + BitmapFilter::Filter(maBitmapEx, BitmapColorQuantizationFilter(nNewColorCount)); + } + else + { + bRet = false; + } + + return bRet; +} + +bool Animation::Invert() +{ + SAL_WARN_IF(IsInAnimation(), "vcl", "Animation modified while it is animated"); + + bool bRet; + + if (!IsInAnimation() && !maList.empty()) + { + bRet = true; + + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + bRet = maList[i]->maBitmapEx.Invert(); + + maBitmapEx.Invert(); + } + else + bRet = false; + + return bRet; +} + +void Animation::Mirror(BmpMirrorFlags nMirrorFlags) +{ + SAL_WARN_IF(IsInAnimation(), "vcl", "Animation modified while it is animated"); + + bool bRet; + + if (!IsInAnimation() && !maList.empty()) + { + bRet = true; + + if (nMirrorFlags != BmpMirrorFlags::NONE) + { + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + { + AnimationBitmap* pStepBmp = maList[i].get(); + bRet = pStepBmp->maBitmapEx.Mirror(nMirrorFlags); + if (bRet) + { + if (nMirrorFlags & BmpMirrorFlags::Horizontal) + pStepBmp->maPositionPixel.setX(maGlobalSize.Width() + - pStepBmp->maPositionPixel.X() + - pStepBmp->maSizePixel.Width()); + + if (nMirrorFlags & BmpMirrorFlags::Vertical) + pStepBmp->maPositionPixel.setY(maGlobalSize.Height() + - pStepBmp->maPositionPixel.Y() + - pStepBmp->maSizePixel.Height()); + } + } + + maBitmapEx.Mirror(nMirrorFlags); + } + } +} + +void Animation::Adjust(short nLuminancePercent, short nContrastPercent, short nChannelRPercent, + short nChannelGPercent, short nChannelBPercent, double fGamma, bool bInvert) +{ + SAL_WARN_IF(IsInAnimation(), "vcl", "Animation modified while it is animated"); + + bool bRet; + + if (!IsInAnimation() && !maList.empty()) + { + bRet = true; + + for (size_t i = 0, n = maList.size(); (i < n) && bRet; ++i) + { + bRet = maList[i]->maBitmapEx.Adjust(nLuminancePercent, nContrastPercent, + nChannelRPercent, nChannelGPercent, + nChannelBPercent, fGamma, bInvert); + } + + maBitmapEx.Adjust(nLuminancePercent, nContrastPercent, nChannelRPercent, nChannelGPercent, + nChannelBPercent, fGamma, bInvert); + } +} + +SvStream& WriteAnimation(SvStream& rOStm, const Animation& rAnimation) +{ + const sal_uInt16 nCount = rAnimation.Count(); + + if (nCount) + { + const sal_uInt32 nDummy32 = 0; + + // If no BitmapEx was set we write the first Bitmap of + // the Animation + if (!rAnimation.GetBitmapEx().GetBitmap()) + WriteDIBBitmapEx(rAnimation.Get(0).maBitmapEx, rOStm); + else + WriteDIBBitmapEx(rAnimation.GetBitmapEx(), rOStm); + + // Write identifier ( SDANIMA1 ) + rOStm.WriteUInt32(0x5344414e).WriteUInt32(0x494d4931); + + for (sal_uInt16 i = 0; i < nCount; i++) + { + const AnimationBitmap& rAnimationBitmap = rAnimation.Get(i); + const sal_uInt16 nRest = nCount - i - 1; + + // Write AnimationBitmap + WriteDIBBitmapEx(rAnimationBitmap.maBitmapEx, rOStm); + tools::GenericTypeSerializer aSerializer(rOStm); + aSerializer.writePoint(rAnimationBitmap.maPositionPixel); + aSerializer.writeSize(rAnimationBitmap.maSizePixel); + aSerializer.writeSize(rAnimation.maGlobalSize); + rOStm.WriteUInt16((ANIMATION_TIMEOUT_ON_CLICK == rAnimationBitmap.mnWait) + ? 65535 + : rAnimationBitmap.mnWait); + rOStm.WriteUInt16(static_cast(rAnimationBitmap.meDisposal)); + rOStm.WriteBool(rAnimationBitmap.mbUserInput); + rOStm.WriteUInt32(rAnimation.mnLoopCount); + rOStm.WriteUInt32(nDummy32); // Unused + rOStm.WriteUInt32(nDummy32); // Unused + rOStm.WriteUInt32(nDummy32); // Unused + write_uInt16_lenPrefixed_uInt8s_FromOString(rOStm, OString()); // dummy + rOStm.WriteUInt16(nRest); // Count of remaining structures + } + } + + return rOStm; +} + +SvStream& ReadAnimation(SvStream& rIStm, Animation& rAnimation) +{ + sal_uLong nStmPos; + sal_uInt32 nAnimMagic1, nAnimMagic2; + SvStreamEndian nOldFormat = rIStm.GetEndian(); + bool bReadAnimations = false; + + rIStm.SetEndian(SvStreamEndian::LITTLE); + nStmPos = rIStm.Tell(); + rIStm.ReadUInt32(nAnimMagic1).ReadUInt32(nAnimMagic2); + + rAnimation.Clear(); + + // If the BitmapEx at the beginning have already been read (by Graphic) + // we can start reading the AnimationBitmaps right away + if ((nAnimMagic1 == 0x5344414e) && (nAnimMagic2 == 0x494d4931) && !rIStm.GetError()) + bReadAnimations = true; + // Else, we try reading the Bitmap(-Ex) + else + { + rIStm.Seek(nStmPos); + ReadDIBBitmapEx(rAnimation.maBitmapEx, rIStm); + nStmPos = rIStm.Tell(); + rIStm.ReadUInt32(nAnimMagic1).ReadUInt32(nAnimMagic2); + + if ((nAnimMagic1 == 0x5344414e) && (nAnimMagic2 == 0x494d4931) && !rIStm.GetError()) + bReadAnimations = true; + else + rIStm.Seek(nStmPos); + } + + // Read AnimationBitmaps + if (bReadAnimations) + { + AnimationBitmap aAnimationBitmap; + sal_uInt32 nTmp32; + sal_uInt16 nTmp16; + bool cTmp; + + do + { + ReadDIBBitmapEx(aAnimationBitmap.maBitmapEx, rIStm); + tools::GenericTypeSerializer aSerializer(rIStm); + aSerializer.readPoint(aAnimationBitmap.maPositionPixel); + aSerializer.readSize(aAnimationBitmap.maSizePixel); + aSerializer.readSize(rAnimation.maGlobalSize); + rIStm.ReadUInt16(nTmp16); + aAnimationBitmap.mnWait = ((65535 == nTmp16) ? ANIMATION_TIMEOUT_ON_CLICK : nTmp16); + rIStm.ReadUInt16(nTmp16); + aAnimationBitmap.meDisposal = static_cast(nTmp16); + rIStm.ReadCharAsBool(cTmp); + aAnimationBitmap.mbUserInput = cTmp; + rIStm.ReadUInt32(rAnimation.mnLoopCount); + rIStm.ReadUInt32(nTmp32); // Unused + rIStm.ReadUInt32(nTmp32); // Unused + rIStm.ReadUInt32(nTmp32); // Unused + read_uInt16_lenPrefixed_uInt8s_ToOString(rIStm); // Unused + rIStm.ReadUInt16(nTmp16); // The rest to read + + rAnimation.Insert(aAnimationBitmap); + } while (nTmp16 && !rIStm.GetError()); + + rAnimation.ResetLoopCount(); + } + + rIStm.SetEndian(nOldFormat); + + return rIStm; +} + +AInfo::AInfo() + : pOutDev(nullptr) + , pViewData(nullptr) + , nExtraData(0) + , bPause(false) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/animate/AnimationBitmap.cxx b/vcl/source/animate/AnimationBitmap.cxx new file mode 100644 index 000000000..7ebaf98d9 --- /dev/null +++ b/vcl/source/animate/AnimationBitmap.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +BitmapChecksum AnimationBitmap::GetChecksum() const +{ + BitmapChecksum nCrc = maBitmapEx.GetChecksum(); + SVBT32 aBT32; + + Int32ToSVBT32(maPositionPixel.X(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(maPositionPixel.Y(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(maSizePixel.Width(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(maSizePixel.Height(), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + Int32ToSVBT32(mnWait, aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + UInt32ToSVBT32(o3tl::underlyingEnumValue(meDisposal), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + UInt32ToSVBT32(sal_uInt32(mbUserInput), aBT32); + nCrc = vcl_get_checksum(nCrc, aBT32, 4); + + return nCrc; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/ITiledRenderable.cxx b/vcl/source/app/ITiledRenderable.cxx new file mode 100644 index 000000000..e2a639dec --- /dev/null +++ b/vcl/source/app/ITiledRenderable.cxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +namespace vcl +{ + + /* + * Map directly to css cursor styles to avoid further mapping in the client. + * Gtk (via gdk_cursor_new_from_name) also supports the same css cursor styles. + * + * This was created partially with help of the mappings in gtkdata.cxx. + * The list is incomplete as some cursor style simply aren't supported + * by css, it might turn out to be worth mapping some of these missing cursors + * to available cursors? + */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning( disable : 4592) +#endif + const std::map gaLOKPointerMap { + { PointerStyle::Arrow, "default" }, + // PointerStyle::Null ? + { PointerStyle::Wait, "wait" }, + { PointerStyle::Text, "text" }, + { PointerStyle::Help, "help" }, + { PointerStyle::Cross, "crosshair" }, + { PointerStyle::Fill, "fill" }, + { PointerStyle::Move, "move" }, + { PointerStyle::NSize, "n-resize" }, + { PointerStyle::SSize, "s-resize" }, + { PointerStyle::WSize, "w-resize" }, + { PointerStyle::ESize, "e-resize" }, + { PointerStyle::NWSize, "ne-resize" }, + { PointerStyle::NESize, "ne-resize" }, + { PointerStyle::SWSize, "sw-resize" }, + { PointerStyle::SESize, "se-resize" }, + // WindowNSize through WindowSESize + { PointerStyle::HSplit, "col-resize" }, + { PointerStyle::VSplit, "row-resize" }, + { PointerStyle::HSizeBar, "col-resize" }, + { PointerStyle::VSizeBar, "row-resize" }, + { PointerStyle::Hand, "grab" }, + { PointerStyle::RefHand, "pointer" }, + // Pen, Magnify, Fill, Rotate + // HShear, VShear + // Mirror, Crook, Crop, MovePoint, MoveBezierWeight + // MoveData + { PointerStyle::CopyData, "copy" }, + { PointerStyle::LinkData, "alias" }, + // MoveDataLink, CopyDataLink + //MoveFile, CopyFile, LinkFile + // MoveFileLink, CopyFileLink, MoveFiless, CopyFiles + { PointerStyle::NotAllowed, "not-allowed" }, + // DrawLine through DrawCaption + // Chart, Detective, PivotCol, PivotRow, PivotField, Chain, ChainNotAllowed + // TimeEventMove, TimeEventSize + // AutoScrollN through AutoScrollNSWE + // Airbrush + { PointerStyle::TextVertical, "vertical-text" } + // Pivot Delete, TabSelectS through TabSelectSW + // PaintBrush, HideWhiteSpace, ShowWhiteSpace + }; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +ITiledRenderable::~ITiledRenderable() +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/IconThemeInfo.cxx b/vcl/source/app/IconThemeInfo.cxx new file mode 100644 index 000000000..84d85883b --- /dev/null +++ b/vcl/source/app/IconThemeInfo.cxx @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include + +// constants for theme ids and display names. Only the theme id for high contrast is used +// outside of this class and hence made public. + +const OUStringLiteral vcl::IconThemeInfo::HIGH_CONTRAST_ID("sifr"); + +namespace { + +static const OUStringLiteral KARASA_JAGA_ID("karasa_jaga"); +static const OUStringLiteral KARASA_JAGA_DISPLAY_NAME("Karasa Jaga"); +static const OUStringLiteral HELPIMG_FAKE_THEME("helpimg"); + +OUString +filename_from_url(const OUString& url) +{ + sal_Int32 slashPosition = url.lastIndexOf( '/' ); + if (slashPosition < 0) { + return OUString(); + } + OUString filename = url.copy( slashPosition+1 ); + return filename; +} + +} // end anonymous namespace + +namespace vcl { + +static const char ICON_THEME_PACKAGE_PREFIX[] = "images_"; + +static const char EXTENSION_FOR_ICON_PACKAGES[] = ".zip"; + +IconThemeInfo::IconThemeInfo() +{ +} + +IconThemeInfo::IconThemeInfo(const OUString& urlToFile) +: mUrlToFile(urlToFile) +{ + OUString filename = filename_from_url(urlToFile); + if (filename.isEmpty()) { + throw std::runtime_error("invalid URL passed to IconThemeInfo()"); + } + + mThemeId = FileNameToThemeId(filename); + mDisplayName = ThemeIdToDisplayName(mThemeId); + +} + +/*static*/ Size +IconThemeInfo::SizeByThemeName(const OUString& themeName) +{ + if (themeName == "galaxy") { //kept for compiler because of unused parameter 'themeName' + return Size( 26, 26 ); + } + else { + return Size( 24, 24 ); + } +} + +/*static*/ bool +IconThemeInfo::UrlCanBeParsed(const OUString& url) +{ + OUString fname = filename_from_url(url); + if (fname.isEmpty()) { + return false; + } + + if (!fname.startsWithIgnoreAsciiCase(ICON_THEME_PACKAGE_PREFIX)) { + return false; + } + + if (!fname.endsWithIgnoreAsciiCase(EXTENSION_FOR_ICON_PACKAGES)) { + return false; + } + + if (fname.indexOf(HELPIMG_FAKE_THEME) != -1 ) { + return false; + } + + return true; +} + +/*static*/ OUString +IconThemeInfo::FileNameToThemeId(const OUString& filename) +{ + OUString r; + sal_Int32 positionOfLastDot = filename.lastIndexOf(EXTENSION_FOR_ICON_PACKAGES); + if (positionOfLastDot < 0) { // -1 means index not found + throw std::runtime_error("IconThemeInfo::FileNameToThemeId() called with invalid filename."); + } + sal_Int32 positionOfFirstUnderscore = filename.indexOf(ICON_THEME_PACKAGE_PREFIX); + if (positionOfFirstUnderscore < 0) { // -1 means index not found. Use the whole name instead + throw std::runtime_error("IconThemeInfo::FileNameToThemeId() called with invalid filename."); + } + positionOfFirstUnderscore += RTL_CONSTASCII_LENGTH(ICON_THEME_PACKAGE_PREFIX); + r = filename.copy(positionOfFirstUnderscore, positionOfLastDot - positionOfFirstUnderscore); + return r; +} + +/*static*/ OUString +IconThemeInfo::ThemeIdToDisplayName(const OUString& themeId) +{ + if (themeId.isEmpty()) { + throw std::runtime_error("IconThemeInfo::ThemeIdToDisplayName() called with invalid id."); + } + + // Strip _svg and _dark filename "extensions" + OUString aDisplayName = themeId; + + bool bIsSvg = aDisplayName.endsWith("_svg", &aDisplayName); + bool bIsDark = aDisplayName.endsWith("_dark", &aDisplayName); + if (!bIsSvg && bIsDark) + bIsSvg = aDisplayName.endsWith("_svg", &aDisplayName); + + // special cases + if (aDisplayName.equalsIgnoreAsciiCase(KARASA_JAGA_ID)) { + aDisplayName = KARASA_JAGA_DISPLAY_NAME; + } + else + { + // make the first letter uppercase + sal_Unicode firstLetter = aDisplayName[0]; + if (rtl::isAsciiLowerCase(firstLetter)) + { + aDisplayName = OUStringChar(sal_Unicode(rtl::toAsciiUpperCase(firstLetter))) + aDisplayName.copy(1); + } + } + + if (bIsSvg && bIsDark) + aDisplayName += " (SVG + dark)"; + else if (bIsSvg) + aDisplayName += " (SVG)"; + else if (bIsDark) + aDisplayName += " (dark)"; + + return aDisplayName; +} + +namespace +{ + class SameTheme + { + private: + const OUString& m_rThemeId; + public: + explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {} + bool operator()(const vcl::IconThemeInfo &rInfo) + { + return m_rThemeId == rInfo.GetThemeId(); + } + }; +} + +/*static*/ const vcl::IconThemeInfo& +IconThemeInfo::FindIconThemeById(const std::vector& themes, const OUString& themeId) +{ + std::vector::const_iterator it = std::find_if(themes.begin(), themes.end(), + SameTheme(themeId)); + if (it == themes.end()) + { + throw std::runtime_error("Could not find theme id in theme vector."); + } + return *it; +} + +/*static*/ bool +IconThemeInfo::IconThemeIsInVector(const std::vector& themes, const OUString& themeId) +{ + return std::any_of(themes.begin(), themes.end(), SameTheme(themeId)); +} + +} // end namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/IconThemeScanner.cxx b/vcl/source/app/IconThemeScanner.cxx new file mode 100644 index 000000000..a9163af3c --- /dev/null +++ b/vcl/source/app/IconThemeScanner.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include + +namespace vcl { + +namespace { + +// set the status of a file. Returns false if the status could not be determined. +bool set_file_status(osl::FileStatus& status, const OUString& file) +{ + osl::DirectoryItem dirItem; + osl::FileBase::RC retvalGet = osl::DirectoryItem::get(file, dirItem); + if (retvalGet != osl::FileBase::E_None) { + SAL_WARN("vcl.app", "Could not determine status for file '" << file << "'."); + return false; + } + osl::FileBase::RC retvalStatus = dirItem.getFileStatus(status); + if (retvalStatus != osl::FileBase::E_None) { + SAL_WARN("vcl.app", "Could not determine status for file '" << file << "'."); + return false; + } + return true; +} + +OUString convert_to_absolute_path(const OUString& path) +{ + salhelper::LinkResolver resolver(0); + osl::FileBase::RC rc = resolver.fetchFileStatus(path); + if (rc != osl::FileBase::E_None) { + SAL_WARN("vcl.app", "Could not resolve path '" << path << "' to search for icon themes."); + if (rc == osl::FileBase::E_MULTIHOP) + { + throw std::runtime_error("Provided a recursive symlink to an icon theme directory that could not be resolved."); + } + } + return resolver.m_aStatus.getFileURL(); +} + +} + +IconThemeScanner::IconThemeScanner() +{} + +void IconThemeScanner::ScanDirectoryForIconThemes(const OUString& paths) +{ + mFoundIconThemes.clear(); + + std::deque aPaths; + + sal_Int32 nIndex = 0; + do + { + aPaths.push_front(paths.getToken(0, ';', nIndex)); + } + while (nIndex >= 0); + + for (const auto& path : aPaths) + { + osl::FileStatus fileStatus(osl_FileStatus_Mask_Type); + bool couldSetFileStatus = set_file_status(fileStatus, path); + if (!couldSetFileStatus) { + continue; + } + + if (!fileStatus.isDirectory()) { + SAL_INFO("vcl.app", "Cannot search for icon themes in '"<< path << "'. It is not a directory."); + continue; + } + + std::vector iconThemePaths = ReadIconThemesFromPath(path); + if (iconThemePaths.empty()) { + SAL_WARN("vcl.app", "Could not find any icon themes in the provided directory ('" < +IconThemeScanner::ReadIconThemesFromPath(const OUString& dir) +{ + std::vector found; + SAL_INFO("vcl.app", "Scanning directory '" << dir << " for icon themes."); + + osl::Directory dirToScan(dir); + osl::FileBase::RC retvalOpen = dirToScan.open(); + if (retvalOpen != osl::FileBase::E_None) { + return found; + } + + osl::DirectoryItem directoryItem; + while (dirToScan.getNextItem(directoryItem) == osl::FileBase::E_None) { + osl::FileStatus status(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName); + osl::FileBase::RC retvalStatus = directoryItem.getFileStatus(status); + if (retvalStatus != osl::FileBase::E_None) { + continue; + } + + OUString filename = convert_to_absolute_path(status.getFileURL()); + if (!FileIsValidIconTheme(filename)) { + continue; + } + found.push_back(filename); + } + return found; +} + +/*static*/ bool +IconThemeScanner::FileIsValidIconTheme(const OUString& filename) +{ + // check whether we can construct an IconThemeInfo from it + if (!IconThemeInfo::UrlCanBeParsed(filename)) { + SAL_INFO("vcl.app", "File '" << filename << "' does not seem to be an icon theme."); + return false; + } + + osl::FileStatus fileStatus(osl_FileStatus_Mask_Type); + bool couldSetFileStatus = set_file_status(fileStatus, filename); + if (!couldSetFileStatus) { + return false; + } + + if (!fileStatus.isRegular()) { + return false; + } + return true; +} + +bool +IconThemeScanner::IconThemeIsInstalled(const OUString& themeId) const +{ + return IconThemeInfo::IconThemeIsInVector(mFoundIconThemes, themeId); +} + +/*static*/ std::shared_ptr +IconThemeScanner::Create(const OUString &path) +{ + std::shared_ptr retval(new IconThemeScanner); + retval->ScanDirectoryForIconThemes(path); + return retval; +} + +/*static*/ OUString +IconThemeScanner::GetStandardIconThemePath() +{ + SvtPathOptions aPathOptions; + return aPathOptions.GetIconsetPath(); +} + +namespace +{ + class SameTheme + { + private: + const OUString& m_rThemeId; + public: + explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {} + bool operator()(const vcl::IconThemeInfo &rInfo) + { + return m_rThemeId == rInfo.GetThemeId(); + } + }; +} + +const vcl::IconThemeInfo& +IconThemeScanner::GetIconThemeInfo(const OUString& themeId) +{ + std::vector::iterator info = std::find_if(mFoundIconThemes.begin(), mFoundIconThemes.end(), + SameTheme(themeId)); + if (info == mFoundIconThemes.end()) { + SAL_WARN("vcl.app", "Requested information for icon theme with id '" << themeId + << "' which does not exist."); + throw std::runtime_error("Requested information on not-installed icon theme"); + } + return *info; +} + +} // end namespace vcl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/IconThemeSelector.cxx b/vcl/source/app/IconThemeSelector.cxx new file mode 100644 index 000000000..e98d63657 --- /dev/null +++ b/vcl/source/app/IconThemeSelector.cxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +#include + +#include +#include + +#include + +namespace vcl { + +/*static*/ const OUStringLiteral IconThemeSelector::FALLBACK_ICON_THEME_ID("colibre"); + +namespace { + + class SameTheme + { + private: + const OUString& m_rThemeId; + public: + explicit SameTheme(const OUString &rThemeId) : m_rThemeId(rThemeId) {} + bool operator()(const vcl::IconThemeInfo &rInfo) + { + return m_rThemeId == rInfo.GetThemeId(); + } + }; + +bool icon_theme_is_in_installed_themes(const OUString& theme, + const std::vector& installedThemes) +{ + return std::any_of(installedThemes.begin(), installedThemes.end(), + SameTheme(theme)); +} + +} // end anonymous namespace + +IconThemeSelector::IconThemeSelector() + : mUseHighContrastTheme(false) + , mPreferDarkIconTheme(false) +{ +} + +/*static*/ OUString +IconThemeSelector::GetIconThemeForDesktopEnvironment(const OUString& desktopEnvironment) +{ + if (comphelper::LibreOfficeKit::isActive()) + return "colibre"; + +#ifdef _WIN32 + (void)desktopEnvironment; + return "colibre"; +#else + OUString r; + if ( desktopEnvironment.equalsIgnoreAsciiCase("plasma5") || + desktopEnvironment.equalsIgnoreAsciiCase("lxqt") ) { + r = "breeze"; + } + else if ( desktopEnvironment.equalsIgnoreAsciiCase("macosx") ) { + r = "sukapura"; + } + else if ( desktopEnvironment.equalsIgnoreAsciiCase("gnome") || + desktopEnvironment.equalsIgnoreAsciiCase("mate") || + desktopEnvironment.equalsIgnoreAsciiCase("unity") ) { + r = "elementary"; + } else + { + r = FALLBACK_ICON_THEME_ID; + } + return r; +#endif // _WIN32 +} + +OUString +IconThemeSelector::SelectIconThemeForDesktopEnvironment( + const std::vector& installedThemes, + const OUString& desktopEnvironment) const +{ + if (!mPreferredIconTheme.isEmpty()) { + if (icon_theme_is_in_installed_themes(mPreferredIconTheme, installedThemes)) { + return mPreferredIconTheme; + } + //if a dark variant is preferred, and we didn't have an exact match, then try our one and only dark theme + if (mPreferDarkIconTheme && icon_theme_is_in_installed_themes("breeze_dark", installedThemes)) { + return "breeze_dark"; + } + } + + OUString themeForDesktop = GetIconThemeForDesktopEnvironment(desktopEnvironment); + if (icon_theme_is_in_installed_themes(themeForDesktop, installedThemes)) { + return themeForDesktop; + } + + return ReturnFallback(installedThemes); +} + +OUString +IconThemeSelector::SelectIconTheme( + const std::vector& installedThemes, + const OUString& theme) const +{ + if (mUseHighContrastTheme) { + if (icon_theme_is_in_installed_themes(IconThemeInfo::HIGH_CONTRAST_ID, installedThemes)) { + return IconThemeInfo::HIGH_CONTRAST_ID; + } + } + + if (icon_theme_is_in_installed_themes(theme, installedThemes)) { + return theme; + } + + return ReturnFallback(installedThemes); +} + +void +IconThemeSelector::SetUseHighContrastTheme(bool v) +{ + mUseHighContrastTheme = v; +} + +void +IconThemeSelector::SetPreferredIconTheme(const OUString& theme, bool bDarkIconTheme) +{ + // lower case theme name, and (tdf#120175) replace - with _ + // see icon-themes/README + mPreferredIconTheme = theme.toAsciiLowerCase().replace('-','_'); + mPreferDarkIconTheme = bDarkIconTheme; +} + +bool +IconThemeSelector::operator==(const vcl::IconThemeSelector& other) const +{ + if (this == &other) { + return true; + } + if (mPreferredIconTheme != other.mPreferredIconTheme) { + return false; + } + if (mPreferDarkIconTheme != other.mPreferDarkIconTheme) { + return false; + } + if (mUseHighContrastTheme != other.mUseHighContrastTheme) { + return false; + } + return true; +} + +bool +IconThemeSelector::operator!=(const vcl::IconThemeSelector& other) const +{ + return !(*this == other); +} + +/*static*/ OUString +IconThemeSelector::ReturnFallback(const std::vector& installedThemes) +{ + if (!installedThemes.empty()) { + return installedThemes.front().GetThemeId(); + } + else { + return FALLBACK_ICON_THEME_ID; + } +} + +} /* namespace vcl */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/brand.cxx b/vcl/source/app/brand.cxx new file mode 100644 index 000000000..290606106 --- /dev/null +++ b/vcl/source/app/brand.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + bool loadPng( const OUString & rPath, BitmapEx &rBitmap) + { + INetURLObject aObj( rPath ); + SvFileStream aStrm( aObj.PathToFileName(), StreamMode::STD_READ ); + if ( !aStrm.GetError() ) { + vcl::PNGReader aReader( aStrm ); + rBitmap = aReader.Read(); + return !rBitmap.IsEmpty(); + } + else + return false; + } + bool tryLoadPng( const OUString& rBaseDir, const OUString& rName, BitmapEx& rBitmap ) + { + return loadPng( rBaseDir + "/" LIBO_ETC_FOLDER + rName, rBitmap); + } +} + +bool Application::LoadBrandBitmap (const char* pName, BitmapEx &rBitmap) +{ + // TODO - if we want more flexibility we could add a branding path + // in an rc file perhaps fallback to "about.bmp" + OUString aBaseDir( "$BRAND_BASE_DIR"); + rtl::Bootstrap::expandMacros( aBaseDir ); + OUString aBaseName( "/" + OUString::createFromAscii( pName ) ); + OUString aPng( ".png" ); + + rtl_Locale *pLoc = nullptr; + osl_getProcessLocale (&pLoc); + LanguageTag aLanguageTag( *pLoc); + + ::std::vector< OUString > aFallbacks( aLanguageTag.getFallbackStrings( true)); + for (const OUString & aFallback : aFallbacks) + { + if (tryLoadPng( aBaseDir, aBaseName + "-" + aFallback + aPng, rBitmap)) + return true; + } + + return tryLoadPng( aBaseDir, aBaseName + aPng, rBitmap); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/customweld.cxx b/vcl/source/app/customweld.cxx new file mode 100644 index 000000000..c08a38208 --- /dev/null +++ b/vcl/source/app/customweld.cxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +namespace weld +{ +CustomWidgetController::~CustomWidgetController() {} + +IMPL_LINK_NOARG(CustomWidgetController, DragBeginHdl, weld::DrawingArea&, bool) +{ + return StartDrag(); +} + +CustomWeld::CustomWeld(weld::Builder& rBuilder, const OString& rDrawingId, + CustomWidgetController& rWidgetController) + : m_rWidgetController(rWidgetController) + , m_xDrawingArea(rBuilder.weld_drawing_area(rDrawingId, rWidgetController.CreateAccessible(), + rWidgetController.GetUITestFactory(), + &rWidgetController)) +{ + m_xDrawingArea->connect_size_allocate(LINK(this, CustomWeld, DoResize)); + m_xDrawingArea->connect_draw(LINK(this, CustomWeld, DoPaint)); + m_xDrawingArea->connect_mouse_press(LINK(this, CustomWeld, DoMouseButtonDown)); + m_xDrawingArea->connect_mouse_move(LINK(this, CustomWeld, DoMouseMove)); + m_xDrawingArea->connect_mouse_release(LINK(this, CustomWeld, DoMouseButtonUp)); + m_xDrawingArea->connect_focus_in(LINK(this, CustomWeld, DoGetFocus)); + m_xDrawingArea->connect_focus_out(LINK(this, CustomWeld, DoLoseFocus)); + m_xDrawingArea->connect_key_press(LINK(this, CustomWeld, DoKeyPress)); + m_xDrawingArea->connect_focus_rect(LINK(this, CustomWeld, DoFocusRect)); + m_xDrawingArea->connect_style_updated(LINK(this, CustomWeld, DoStyleUpdated)); + m_xDrawingArea->connect_command(LINK(this, CustomWeld, DoCommand)); + m_xDrawingArea->connect_query_tooltip(LINK(this, CustomWeld, DoRequestHelp)); + m_xDrawingArea->connect_im_context_get_surrounding(LINK(this, CustomWeld, DoGetSurrounding)); + m_rWidgetController.SetDrawingArea(m_xDrawingArea.get()); +} + +IMPL_LINK(CustomWeld, DoResize, const Size&, rSize, void) +{ + m_rWidgetController.SetOutputSizePixel(rSize); + m_rWidgetController.Resize(); +} + +IMPL_LINK(CustomWeld, DoPaint, weld::DrawingArea::draw_args, aPayload, void) +{ + m_rWidgetController.Paint(aPayload.first, aPayload.second); +} + +IMPL_LINK(CustomWeld, DoMouseButtonDown, const MouseEvent&, rMEvt, bool) +{ + return m_rWidgetController.MouseButtonDown(rMEvt); +} + +IMPL_LINK(CustomWeld, DoMouseMove, const MouseEvent&, rMEvt, bool) +{ + return m_rWidgetController.MouseMove(rMEvt); +} + +IMPL_LINK(CustomWeld, DoMouseButtonUp, const MouseEvent&, rMEvt, bool) +{ + return m_rWidgetController.MouseButtonUp(rMEvt); +} + +IMPL_LINK_NOARG(CustomWeld, DoGetFocus, weld::Widget&, void) { m_rWidgetController.GetFocus(); } + +IMPL_LINK_NOARG(CustomWeld, DoLoseFocus, weld::Widget&, void) { m_rWidgetController.LoseFocus(); } + +IMPL_LINK(CustomWeld, DoKeyPress, const KeyEvent&, rKEvt, bool) +{ + return m_rWidgetController.KeyInput(rKEvt); +} + +IMPL_LINK_NOARG(CustomWeld, DoFocusRect, weld::Widget&, tools::Rectangle) +{ + return m_rWidgetController.GetFocusRect(); +} + +IMPL_LINK_NOARG(CustomWeld, DoStyleUpdated, weld::Widget&, void) +{ + m_rWidgetController.StyleUpdated(); +} + +IMPL_LINK(CustomWeld, DoCommand, const CommandEvent&, rPos, bool) +{ + return m_rWidgetController.Command(rPos); +} + +IMPL_LINK(CustomWeld, DoRequestHelp, tools::Rectangle&, rHelpArea, OUString) +{ + return m_rWidgetController.RequestHelp(rHelpArea); +} + +IMPL_LINK(CustomWeld, DoGetSurrounding, OUString&, rSurrounding, int) +{ + return m_rWidgetController.GetSurroundingText(rSurrounding); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/dbggui.cxx b/vcl/source/app/dbggui.cxx new file mode 100644 index 000000000..cfeeeaf5d --- /dev/null +++ b/vcl/source/app/dbggui.cxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#ifndef NDEBUG + +#include + +#include +#include + +#include + +using namespace ::com::sun::star; + +static void ImplDbgTestSolarMutex() +{ + assert(ImplGetSVData()->mpDefInst->GetYieldMutex()->IsCurrentThread() && "SolarMutex not owned!"); +} + +void DbgGUIInitSolarMutexCheck() +{ + DbgSetTestSolarMutex( ImplDbgTestSolarMutex ); +} + +void DbgGUIDeInitSolarMutexCheck() +{ + DbgSetTestSolarMutex( nullptr ); +} + +#endif // NDEBUG + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/dndhelp.cxx b/vcl/source/app/dndhelp.cxx new file mode 100644 index 000000000..ff4beb789 --- /dev/null +++ b/vcl/source/app/dndhelp.cxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +using namespace ::com::sun::star; + +vcl::unohelper::DragAndDropClient::~DragAndDropClient() COVERITY_NOEXCEPT_FALSE {} + +void vcl::unohelper::DragAndDropClient::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& /*dge*/ ) +{ +} + +void vcl::unohelper::DragAndDropClient::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& /*dsde*/ ) +{ +} + +void vcl::unohelper::DragAndDropClient::drop( const css::datatransfer::dnd::DropTargetDropEvent& /*dtde*/ ) +{ +} + +void vcl::unohelper::DragAndDropClient::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& /*dtdee*/ ) +{ +} + +void vcl::unohelper::DragAndDropClient::dragExit( const css::datatransfer::dnd::DropTargetEvent& /*dte*/ ) +{ +} + +void vcl::unohelper::DragAndDropClient::dragOver( const css::datatransfer::dnd::DropTargetDragEvent& /*dtde*/ ) +{ +} + +vcl::unohelper::DragAndDropWrapper::DragAndDropWrapper( DragAndDropClient* pClient ) +{ + mpClient = pClient; +} + +vcl::unohelper::DragAndDropWrapper::~DragAndDropWrapper() +{ +} + +// uno::XInterface +uno::Any vcl::unohelper::DragAndDropWrapper::queryInterface( const uno::Type & rType ) +{ + uno::Any aRet = ::cppu::queryInterface( rType, + static_cast< css::lang::XEventListener* >( static_cast(this) ), + static_cast< css::datatransfer::dnd::XDragGestureListener* >(this), + static_cast< css::datatransfer::dnd::XDragSourceListener* >(this), + static_cast< css::datatransfer::dnd::XDropTargetListener* >(this) ); + return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); +} + +// css::lang::XEventListener +void vcl::unohelper::DragAndDropWrapper::disposing( const css::lang::EventObject& rEvent ) +{ + // Empty Source means it's the client, because the client is not a XInterface + if ( !rEvent.Source.is() ) + mpClient = nullptr; +} + +// css::datatransfer::dnd::XDragGestureListener +void vcl::unohelper::DragAndDropWrapper::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent& rDGE ) +{ + if ( mpClient ) + mpClient->dragGestureRecognized( rDGE ); +} + +// css::datatransfer::dnd::XDragSourceListener +void vcl::unohelper::DragAndDropWrapper::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent& rDSDE ) +{ + if ( mpClient ) + mpClient->dragDropEnd( rDSDE ); +} + +void vcl::unohelper::DragAndDropWrapper::dragEnter( const css::datatransfer::dnd::DragSourceDragEvent& ) +{ +} + +void vcl::unohelper::DragAndDropWrapper::dragExit( const css::datatransfer::dnd::DragSourceEvent& ) +{ +} + +void vcl::unohelper::DragAndDropWrapper::dragOver( const css::datatransfer::dnd::DragSourceDragEvent& ) +{ +} + +void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const css::datatransfer::dnd::DragSourceDragEvent& ) +{ +} + +// css::datatransfer::dnd::XDropTargetListener +void vcl::unohelper::DragAndDropWrapper::drop( const css::datatransfer::dnd::DropTargetDropEvent& rDTDE ) +{ + if ( mpClient ) + mpClient->drop( rDTDE ); +} + +void vcl::unohelper::DragAndDropWrapper::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE ) +{ + if ( mpClient ) + mpClient->dragEnter( rDTDEE ); +} + +void vcl::unohelper::DragAndDropWrapper::dragExit( const css::datatransfer::dnd::DropTargetEvent& dte ) +{ + if ( mpClient ) + mpClient->dragExit( dte ); +} + +void vcl::unohelper::DragAndDropWrapper::dragOver( const css::datatransfer::dnd::DropTargetDragEvent& rDTDE ) +{ + if ( mpClient ) + mpClient->dragOver( rDTDE ); +} + +void vcl::unohelper::DragAndDropWrapper::dropActionChanged( const css::datatransfer::dnd::DropTargetDragEvent& ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx new file mode 100644 index 000000000..ebe7588c5 --- /dev/null +++ b/vcl/source/app/help.cxx @@ -0,0 +1,677 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define HELPWINSTYLE_QUICK 0 +#define HELPWINSTYLE_BALLOON 1 + +#define HELPTEXTMARGIN_QUICK 3 +#define HELPTEXTMARGIN_BALLOON 6 + +#define HELPTEXTMAXLEN 150 + +Help::Help() +{ +} + +Help::~Help() +{ +} + +bool Help::Start( const OUString&, const vcl::Window* ) +{ + return false; +} + +bool Help::Start(const OUString&, weld::Widget*) +{ + return false; +} + +void Help::SearchKeyword( const OUString& ) +{ +} + +OUString Help::GetHelpText( const OUString&, const vcl::Window* ) +{ + return OUString(); +} + +OUString Help::GetHelpText( const OUString&, const weld::Widget* ) +{ + return OUString(); +} + +void Help::EnableContextHelp() +{ + ImplGetSVHelpData().mbContextHelp = true; +} + +void Help::DisableContextHelp() +{ + ImplGetSVHelpData().mbContextHelp = false; +} + +bool Help::IsContextHelpEnabled() +{ + return ImplGetSVHelpData().mbContextHelp; +} + +void Help::EnableExtHelp() +{ + ImplGetSVHelpData().mbExtHelp = true; +} + +void Help::DisableExtHelp() +{ + ImplGetSVHelpData().mbExtHelp = false; +} + +bool Help::IsExtHelpEnabled() +{ + return ImplGetSVHelpData().mbExtHelp; +} + +bool Help::StartExtHelp() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplSVHelpData& aHelpData = ImplGetSVHelpData(); + + if ( aHelpData.mbExtHelp && !aHelpData.mbExtHelpMode ) + { + aHelpData.mbExtHelpMode = true; + aHelpData.mbOldBalloonMode = aHelpData.mbBalloonHelp; + aHelpData.mbBalloonHelp = true; + if (pSVData->maFrameData.mpAppWin) + pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove(); + return true; + } + + return false; +} + +bool Help::EndExtHelp() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplSVHelpData& aHelpData = ImplGetSVHelpData(); + + if ( aHelpData.mbExtHelp && aHelpData.mbExtHelpMode ) + { + aHelpData.mbExtHelpMode = false; + aHelpData.mbBalloonHelp = aHelpData.mbOldBalloonMode; + if (pSVData->maFrameData.mpAppWin) + pSVData->maFrameData.mpAppWin->ImplGenerateMouseMove(); + return true; + } + + return false; +} + +void Help::EnableBalloonHelp() +{ + ImplGetSVHelpData().mbBalloonHelp = true; +} + +void Help::DisableBalloonHelp() +{ + ImplGetSVHelpData().mbBalloonHelp = false; +} + +bool Help::IsBalloonHelpEnabled() +{ + return ImplGetSVHelpData().mbBalloonHelp; +} + +void Help::ShowBalloon( vcl::Window* pParent, + const Point& rScreenPos, const tools::Rectangle& rRect, + const OUString& rHelpText ) +{ + ImplShowHelpWindow( pParent, HELPWINSTYLE_BALLOON, QuickHelpFlags::NONE, + rHelpText, rScreenPos, rRect ); +} + +void Help::EnableQuickHelp() +{ + ImplGetSVHelpData().mbQuickHelp = true; +} + +void Help::DisableQuickHelp() +{ + ImplGetSVHelpData().mbQuickHelp = false; +} + +bool Help::IsQuickHelpEnabled() +{ + return ImplGetSVHelpData().mbQuickHelp; +} + +void Help::ShowQuickHelp( vcl::Window* pParent, + const tools::Rectangle& rScreenRect, + const OUString& rHelpText, + QuickHelpFlags nStyle ) +{ + sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK; + ImplShowHelpWindow( pParent, nHelpWinStyle, nStyle, + rHelpText, + pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect ); +} + +void Help::HideBalloonAndQuickHelp() +{ + HelpTextWindow const * pHelpWin = ImplGetSVHelpData().mpHelpWin; + bool const bIsVisible = ( pHelpWin != nullptr ) && pHelpWin->IsVisible(); + ImplDestroyHelpWindow( bIsVisible ); +} + +void* Help::ShowPopover(vcl::Window* pParent, const tools::Rectangle& rScreenRect, + const OUString& rText, QuickHelpFlags nStyle) +{ + void* nId = pParent->ImplGetFrame()->ShowPopover(rText, pParent, rScreenRect, nStyle); + if (nId) + { + //popovers are handled natively, return early + return nId; + } + + sal_uInt16 nHelpWinStyle = ( nStyle & QuickHelpFlags::TipStyleBalloon ) ? HELPWINSTYLE_BALLOON : HELPWINSTYLE_QUICK; + VclPtrInstance pHelpWin( pParent, rText, nHelpWinStyle, nStyle ); + + nId = pHelpWin.get(); + UpdatePopover(nId, pParent, rScreenRect, rText); + + pHelpWin->ShowHelp(true); + return nId; +} + +void Help::UpdatePopover(void* nId, vcl::Window* pParent, const tools::Rectangle& rScreenRect, + const OUString& rText) +{ + if (pParent->ImplGetFrame()->UpdatePopover(nId, rText, pParent, rScreenRect)) + { + //popovers are handled natively, return early + return; + } + + HelpTextWindow* pHelpWin = static_cast< HelpTextWindow* >( nId ); + ENSURE_OR_RETURN_VOID( pHelpWin != nullptr, "Help::UpdatePopover: invalid ID!" ); + + Size aSz = pHelpWin->CalcOutSize(); + pHelpWin->SetOutputSizePixel( aSz ); + ImplSetHelpWindowPos( pHelpWin, pHelpWin->GetWinStyle(), pHelpWin->GetStyle(), + pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), rScreenRect ); + + pHelpWin->SetHelpText( rText ); + pHelpWin->Invalidate(); +} + +void Help::HidePopover(vcl::Window const * pParent, void* nId) +{ + if (pParent->ImplGetFrame()->HidePopover(nId)) + { + //popovers are handled natively, return early + return; + } + + VclPtr pHelpWin = static_cast(nId); + vcl::Window* pFrameWindow = pHelpWin->ImplGetFrameWindow(); + pHelpWin->Hide(); + // trigger update, so that a Paint is instantly triggered since we do not save the background + pFrameWindow->ImplUpdateAll(); + pHelpWin.disposeAndClear(); + ImplGetSVHelpData().mnLastHelpHideTime = tools::Time::GetSystemTicks(); +} + +HelpTextWindow::HelpTextWindow( vcl::Window* pParent, const OUString& rText, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle ) : + FloatingWindow( pParent, WB_SYSTEMWINDOW|WB_TOOLTIPWIN ), // #105827# if we change the parent, mirroring will not work correctly when positioning this window + maHelpText( rText ) +{ + SetType( WindowType::HELPTEXTWINDOW ); + ImplSetMouseTransparent( true ); + mnHelpWinStyle = nHelpWinStyle; + mnStyle = nStyle; + + if( mnStyle & QuickHelpFlags::BiDiRtl ) + { + ComplexTextLayoutFlags nLayoutMode = GetLayoutMode(); + nLayoutMode |= ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::TextOriginLeft; + SetLayoutMode( nLayoutMode ); + } + SetHelpText( rText ); + Window::SetHelpText( rText ); + + if ( ImplGetSVHelpData().mbSetKeyboardHelp ) + ImplGetSVHelpData().mbKeyboardHelp = true; + + + maShowTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) ); + maShowTimer.SetDebugName( "vcl::HelpTextWindow maShowTimer" ); + + const HelpSettings& rHelpSettings = pParent->GetSettings().GetHelpSettings(); + maHideTimer.SetTimeout( rHelpSettings.GetTipTimeout() ); + maHideTimer.SetInvokeHandler( LINK( this, HelpTextWindow, TimerHdl ) ); + maHideTimer.SetDebugName( "vcl::HelpTextWindow maHideTimer" ); +} + +void HelpTextWindow::ApplySettings(vcl::RenderContext& rRenderContext) +{ + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + SetPointFont(rRenderContext, rStyleSettings.GetHelpFont()); + rRenderContext.SetTextColor(rStyleSettings.GetHelpTextColor()); + rRenderContext.SetTextAlign(ALIGN_TOP); + + if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire)) + { + EnableChildTransparentMode(); + SetParentClipMode(ParentClipMode::NoClip); + SetPaintTransparent(true); + rRenderContext.SetBackground(); + } + else + rRenderContext.SetBackground(Wallpaper(rStyleSettings.GetHelpColor())); + + if (rStyleSettings.GetHelpColor().IsDark()) + rRenderContext.SetLineColor(COL_WHITE); + else + rRenderContext.SetLineColor(COL_BLACK); + rRenderContext.SetFillColor(); +} + +HelpTextWindow::~HelpTextWindow() +{ + disposeOnce(); +} + +void HelpTextWindow::dispose() +{ + maShowTimer.Stop(); + maHideTimer.Stop(); + + if( this == ImplGetSVHelpData().mpHelpWin ) + ImplGetSVHelpData().mpHelpWin = nullptr; + FloatingWindow::dispose(); +} + +void HelpTextWindow::SetHelpText( const OUString& rHelpText ) +{ + maHelpText = rHelpText; + ApplySettings(*this); + if ( mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0) + { + Size aSize; + aSize.setHeight( GetTextHeight() ); + if ( mnStyle & QuickHelpFlags::CtrlText ) + aSize.setWidth( GetCtrlTextWidth( maHelpText ) ); + else + aSize.setWidth( GetTextWidth( maHelpText ) ); + maTextRect = tools::Rectangle( Point( HELPTEXTMARGIN_QUICK, HELPTEXTMARGIN_QUICK ), aSize ); + } + else // HELPWINSTYLE_BALLOON + { + sal_Int32 nCharsInLine = 35 + ((maHelpText.getLength()/100)*5); + // average width to have all windows consistent + OUStringBuffer aBuf; + comphelper::string::padToLength(aBuf, nCharsInLine, 'x'); + OUString aXXX = aBuf.makeStringAndClear(); + long nWidth = GetTextWidth( aXXX ); + Size aTmpSize( nWidth, 0x7FFFFFFF ); + tools::Rectangle aTry1( Point(), aTmpSize ); + DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine | DrawTextFlags::WordBreak | + DrawTextFlags::Left | DrawTextFlags::Top; + if ( mnStyle & QuickHelpFlags::CtrlText ) + nDrawFlags |= DrawTextFlags::Mnemonic; + tools::Rectangle aTextRect = GetTextRect( aTry1, maHelpText, nDrawFlags ); + + // get a better width later... + maTextRect = aTextRect; + + // safety distance... + maTextRect.SetPos( Point( HELPTEXTMARGIN_BALLOON, HELPTEXTMARGIN_BALLOON ) ); + } + + Size aSize( CalcOutSize() ); + SetOutputSizePixel( aSize ); +} + +void HelpTextWindow::ImplShow() +{ + VclPtr xWindow( this ); + Show( true, ShowFlags::NoActivate ); + if( !xWindow->IsDisposed() ) + PaintImmediately(); +} + +void HelpTextWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) +{ + // paint native background + bool bNativeOK = false; + if (rRenderContext.IsNativeControlSupported(ControlType::Tooltip, ControlPart::Entire)) + { + tools::Rectangle aCtrlRegion(Point(0, 0), GetOutputSizePixel()); + ImplControlValue aControlValue; + bNativeOK = rRenderContext.DrawNativeControl(ControlType::Tooltip, ControlPart::Entire, aCtrlRegion, + ControlState::NONE, aControlValue, OUString()); + } + + // paint text + if (mnHelpWinStyle == HELPWINSTYLE_QUICK && maHelpText.getLength() < HELPTEXTMAXLEN && maHelpText.indexOf('\n') < 0) + { + if ( mnStyle & QuickHelpFlags::CtrlText ) + rRenderContext.DrawCtrlText(maTextRect.TopLeft(), maHelpText); + else + rRenderContext.DrawText(maTextRect.TopLeft(), maHelpText); + } + else // HELPWINSTYLE_BALLOON + { + DrawTextFlags nDrawFlags = DrawTextFlags::MultiLine|DrawTextFlags::WordBreak| + DrawTextFlags::Left|DrawTextFlags::Top; + if (mnStyle & QuickHelpFlags::CtrlText) + nDrawFlags |= DrawTextFlags::Mnemonic; + rRenderContext.DrawText(maTextRect, maHelpText, nDrawFlags); + } + + // border + if (!bNativeOK) + { + Size aSz = GetOutputSizePixel(); + rRenderContext.DrawRect(tools::Rectangle(Point(), aSz)); + if (mnHelpWinStyle == HELPWINSTYLE_BALLOON) + { + aSz.AdjustWidth( -2 ); + aSz.AdjustHeight( -2 ); + Color aColor(rRenderContext.GetLineColor()); + rRenderContext.SetLineColor(COL_GRAY); + rRenderContext.DrawRect(tools::Rectangle(Point(1, 1), aSz)); + rRenderContext.SetLineColor(aColor); + } + } +} + +void HelpTextWindow::ShowHelp(bool bNoDelay) +{ + sal_uLong nTimeout = 0; + if (!bNoDelay) + { + // In case of ExtendedHelp display help sooner + if ( ImplGetSVHelpData().mbExtHelpMode ) + nTimeout = 15; + else + { + if ( mnHelpWinStyle == HELPWINSTYLE_QUICK ) + nTimeout = HelpSettings::GetTipDelay(); + else + nTimeout = HelpSettings::GetBalloonDelay(); + } + } + + maShowTimer.SetTimeout( nTimeout ); + maShowTimer.Start(); +} + +IMPL_LINK( HelpTextWindow, TimerHdl, Timer*, pTimer, void) +{ + if ( pTimer == &maShowTimer ) + { + if ( mnHelpWinStyle == HELPWINSTYLE_QUICK ) + { + // start auto-hide-timer for non-ShowTip windows + if ( this == ImplGetSVHelpData().mpHelpWin ) + maHideTimer.Start(); + } + ImplShow(); + } + else + { + SAL_WARN_IF( pTimer != &maHideTimer, "vcl", "HelpTextWindow::TimerHdl with bad Timer" ); + ImplDestroyHelpWindow( true ); + } +} + +Size HelpTextWindow::CalcOutSize() const +{ + Size aSz = maTextRect.GetSize(); + aSz.AdjustWidth(2*maTextRect.Left() ); + aSz.AdjustHeight(2*maTextRect.Top() ); + return aSz; +} + +void HelpTextWindow::RequestHelp( const HelpEvent& /*rHEvt*/ ) +{ + // Just to assure that Window::RequestHelp() is not called by + // ShowQuickHelp/ShowBalloonHelp in the HelpTextWindow. +} + +OUString HelpTextWindow::GetText() const +{ + return maHelpText; +} + +void ImplShowHelpWindow( vcl::Window* pParent, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle, + const OUString& rHelpText, + const Point& rScreenPos, const tools::Rectangle& rHelpArea ) +{ + if (pParent->ImplGetFrame()->ShowTooltip(rHelpText, rHelpArea)) + { + //tooltips are handled natively, return early + return; + } + + ImplSVHelpData& aHelpData = ImplGetSVHelpData(); + + if (rHelpText.isEmpty() && !aHelpData.mbRequestingHelp) + return; + + VclPtr pHelpWin = aHelpData.mpHelpWin; + bool bNoDelay = false; + if ( pHelpWin ) + { + SAL_WARN_IF( pHelpWin == pParent, "vcl", "HelpInHelp ?!" ); + + if ( ( rHelpText.isEmpty() + || ( pHelpWin->GetWinStyle() != nHelpWinStyle ) + ) + && aHelpData.mbRequestingHelp + ) + { + // remove help window if no HelpText or + // other help mode. but keep it if we are scrolling, ie not requesting help + bool bWasVisible = pHelpWin->IsVisible(); + if ( bWasVisible ) + bNoDelay = true; // display it quickly if we were already in quick help mode + pHelpWin = nullptr; + ImplDestroyHelpWindow( bWasVisible ); + } + else + { + bool const bUpdate = (pHelpWin->GetHelpText() != rHelpText) || + ((pHelpWin->GetHelpArea() != rHelpArea) && aHelpData.mbRequestingHelp); + if (bUpdate) + { + pHelpWin->SetHelpText( rHelpText ); + // approach mouse position + ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea ); + if( pHelpWin->IsVisible() ) + pHelpWin->Invalidate(); + } + } + } + + if (pHelpWin || rHelpText.isEmpty()) + return; + + sal_uInt64 nCurTime = tools::Time::GetSystemTicks(); + if ( ( nCurTime - aHelpData.mnLastHelpHideTime ) < HelpSettings::GetTipDelay() ) + bNoDelay = true; + + pHelpWin = VclPtr::Create( pParent, rHelpText, nHelpWinStyle, nStyle ); + aHelpData.mpHelpWin = pHelpWin; + pHelpWin->SetHelpArea( rHelpArea ); + + // positioning + Size aSz = pHelpWin->CalcOutSize(); + pHelpWin->SetOutputSizePixel( aSz ); + ImplSetHelpWindowPos( pHelpWin, nHelpWinStyle, nStyle, rScreenPos, rHelpArea ); + // if not called from Window::RequestHelp, then without delay... + if ( !aHelpData.mbRequestingHelp ) + bNoDelay = true; + pHelpWin->ShowHelp(bNoDelay); + +} + +void ImplDestroyHelpWindow( bool bUpdateHideTime ) +{ + ImplDestroyHelpWindow(ImplGetSVHelpData(), bUpdateHideTime); +} + +void ImplDestroyHelpWindow(ImplSVHelpData& rHelpData, bool bUpdateHideTime) +{ + VclPtr pHelpWin = rHelpData.mpHelpWin; + if( pHelpWin ) + { + rHelpData.mpHelpWin = nullptr; + rHelpData.mbKeyboardHelp = false; + pHelpWin->Hide(); + pHelpWin.disposeAndClear(); + if( bUpdateHideTime ) + rHelpData.mnLastHelpHideTime = tools::Time::GetSystemTicks(); + } +} + +void ImplSetHelpWindowPos( vcl::Window* pHelpWin, sal_uInt16 nHelpWinStyle, QuickHelpFlags nStyle, + const Point& rPos, const tools::Rectangle& rHelpArea ) +{ + Point aPos = rPos; + Size aSz = pHelpWin->GetSizePixel(); + tools::Rectangle aScreenRect = pHelpWin->ImplGetFrameWindow()->GetDesktopRectPixel(); + aPos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aPos ); + // get mouse screen coords + Point aMousePos( pHelpWin->GetParent()->ImplGetFrameWindow()->GetPointerPosPixel() ); + aMousePos = pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( aMousePos ); + + if ( nHelpWinStyle == HELPWINSTYLE_QUICK ) + { + if ( !(nStyle & QuickHelpFlags::NoAutoPos) ) + { + long nScreenHeight = aScreenRect.GetHeight(); + aPos.AdjustX( -4 ); + if ( aPos.Y() > aScreenRect.Top()+nScreenHeight-(nScreenHeight/4) ) + aPos.AdjustY( -(aSz.Height()+4) ); + else + aPos.AdjustY(21 ); + } + } + else + { + // If it's the mouse position, move the window slightly + // so the mouse pointer does not cover it + if ( aPos == aMousePos ) + { + aPos.AdjustX(12 ); + aPos.AdjustY(16 ); + } + } + + if ( nStyle & QuickHelpFlags::NoAutoPos ) + { + // convert help area to screen coords + tools::Rectangle devHelpArea( + pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( rHelpArea.TopLeft() ), + pHelpWin->GetParent()->ImplGetFrameWindow()->OutputToAbsoluteScreenPixel( rHelpArea.BottomRight() ) ); + + // which position of the rectangle? + aPos = devHelpArea.Center(); + + if ( nStyle & QuickHelpFlags::Left ) + aPos.setX( devHelpArea.Left() ); + else if ( nStyle & QuickHelpFlags::Right ) + aPos.setX( devHelpArea.Right() ); + + if ( nStyle & QuickHelpFlags::Top ) + aPos.setY( devHelpArea.Top() ); + else if ( nStyle & QuickHelpFlags::Bottom ) + aPos.setY( devHelpArea.Bottom() ); + + // which direction? + if ( nStyle & QuickHelpFlags::Left ) + ; + else if ( nStyle & QuickHelpFlags::Right ) + aPos.AdjustX( -(aSz.Width()) ); + else + aPos.AdjustX( -(aSz.Width()/2) ); + + if ( nStyle & QuickHelpFlags::Top ) + ; + else if ( nStyle & QuickHelpFlags::Bottom ) + aPos.AdjustY( -(aSz.Height()) ); + else + aPos.AdjustY( -(aSz.Height()/2) ); + } + + if ( aPos.X() < aScreenRect.Left() ) + aPos.setX( aScreenRect.Left() ); + else if ( ( aPos.X() + aSz.Width() ) > aScreenRect.Right() ) + aPos.setX( aScreenRect.Right() - aSz.Width() ); + if ( aPos.Y() < aScreenRect.Top() ) + aPos.setY( aScreenRect.Top() ); + else if ( ( aPos.Y() + aSz.Height() ) > aScreenRect.Bottom() ) + aPos.setY( aScreenRect.Bottom() - aSz.Height() ); + + if( ! (nStyle & QuickHelpFlags::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... + */ + tools::Rectangle aHelpRect( aPos, aSz ); + if( aHelpRect.IsInside( aMousePos ) ) + { + Point delta(2,2); + Point aSize( aSz.Width(), aSz.Height() ); + Point aTest( aMousePos - aSize - delta ); + if( aTest.X() > aScreenRect.Left() && aTest.Y() > aScreenRect.Top() ) + aPos = aTest; + else + aPos = aMousePos + delta; + } + } + + vcl::Window* pWindow = pHelpWin->GetParent()->ImplGetFrameWindow(); + aPos = pWindow->AbsoluteScreenToOutputPixel( aPos ); + pHelpWin->SetPosPixel( aPos ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/i18nhelp.cxx b/vcl/source/app/i18nhelp.cxx new file mode 100644 index 000000000..ae7eed0e2 --- /dev/null +++ b/vcl/source/app/i18nhelp.cxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include + +#include + +using namespace ::com::sun::star; + +vcl::I18nHelper::I18nHelper( const css::uno::Reference< css::uno::XComponentContext >& rxContext, const LanguageTag& rLanguageTag ) + : + maLanguageTag( rLanguageTag) +{ + m_xContext = rxContext; + mpLocaleDataWrapper = nullptr; + mpTransliterationWrapper= nullptr; + mbTransliterateIgnoreCase = false; +} + +vcl::I18nHelper::~I18nHelper() +{ + ImplDestroyWrappers(); +} + +void vcl::I18nHelper::ImplDestroyWrappers() +{ + mpLocaleDataWrapper.reset(); + mpTransliterationWrapper.reset(); +} + +utl::TransliterationWrapper& vcl::I18nHelper::ImplGetTransliterationWrapper() const +{ + if ( !mpTransliterationWrapper ) + { + TransliterationFlags nModules = TransliterationFlags::IGNORE_WIDTH; + if ( mbTransliterateIgnoreCase ) + nModules |= TransliterationFlags::IGNORE_CASE; + + const_cast(this)->mpTransliterationWrapper.reset(new utl::TransliterationWrapper( m_xContext, nModules )); + const_cast(this)->mpTransliterationWrapper->loadModuleIfNeeded( maLanguageTag.getLanguageType() ); + } + return *mpTransliterationWrapper; +} + +LocaleDataWrapper& vcl::I18nHelper::ImplGetLocaleDataWrapper() const +{ + if ( !mpLocaleDataWrapper ) + { + const_cast(this)->mpLocaleDataWrapper.reset(new LocaleDataWrapper( m_xContext, maLanguageTag )); + } + return *mpLocaleDataWrapper; +} + +static 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 changing 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. +*/ +OUString vcl::I18nHelper::filterFormattingChars( const OUString& rStr ) +{ + sal_Int32 nLength = rStr.getLength(); + OUStringBuffer aBuf( nLength ); + const sal_Unicode* pStr = rStr.getStr(); + while( nLength-- ) + { + if( ! is_formatting_mark( *pStr ) ) + aBuf.append( *pStr ); + pStr++; + } + return aBuf.makeStringAndClear(); +} + +sal_Int32 vcl::I18nHelper::CompareString( const OUString& rStr1, const OUString& rStr2 ) const +{ + ::osl::Guard< ::osl::Mutex > aGuard( const_cast(this)->maMutex ); + + if ( mbTransliterateIgnoreCase ) + { + // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to + // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase + const_cast(this)->mbTransliterateIgnoreCase = false; + const_cast(this)->mpTransliterationWrapper.reset(); + } + + OUString aStr1( filterFormattingChars(rStr1) ); + OUString aStr2( filterFormattingChars(rStr2) ); + return ImplGetTransliterationWrapper().compareString( aStr1, aStr2 ); +} + +bool vcl::I18nHelper::MatchString( const OUString& rStr1, const OUString& rStr2 ) const +{ + ::osl::Guard< ::osl::Mutex > aGuard( const_cast(this)->maMutex ); + + if ( !mbTransliterateIgnoreCase ) + { + // Change mbTransliterateIgnoreCase and destroy the wrapper, next call to + // ImplGetTransliterationWrapper() will create a wrapper with the correct bIgnoreCase + const_cast(this)->mbTransliterateIgnoreCase = true; + const_cast(this)->mpTransliterationWrapper.reset(); + } + + OUString aStr1( filterFormattingChars(rStr1) ); + OUString aStr2( filterFormattingChars(rStr2) ); + return ImplGetTransliterationWrapper().isMatch( aStr1, aStr2 ); +} + +bool vcl::I18nHelper::MatchMnemonic( const OUString& rString, sal_Unicode cMnemonicChar ) const +{ + ::osl::Guard< ::osl::Mutex > aGuard( const_cast(this)->maMutex ); + + bool bEqual = false; + sal_Int32 n = rString.indexOf( '~' ); + if ( n != -1 ) + { + OUString aMatchStr = rString.copy( n+1 ); // not only one char, because of transliteration... + bEqual = MatchString( OUString(cMnemonicChar), aMatchStr ); + } + return bEqual; +} + +OUString vcl::I18nHelper::GetNum( long nNumber, sal_uInt16 nDecimals, bool bUseThousandSep, bool bTrailingZeros ) const +{ + return ImplGetLocaleDataWrapper().getNum( nNumber, nDecimals, bUseThousandSep, bTrailingZeros ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/idle.cxx b/vcl/source/app/idle.cxx new file mode 100644 index 000000000..26e1e5f22 --- /dev/null +++ b/vcl/source/app/idle.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +Idle::Idle( bool bAuto, const char *pDebugName ) + : Timer( bAuto, pDebugName ) +{ + SetPriority( TaskPriority::DEFAULT_IDLE ); +} + +Idle::Idle( const char *pDebugName ) + : Idle( false, pDebugName ) +{ +} + +void Idle::Start() +{ + Task::Start(); + + sal_uInt64 nPeriod = Scheduler::ImmediateTimeoutMs; + if (Scheduler::GetDeterministicMode()) + { + switch ( GetPriority() ) + { + case TaskPriority::DEFAULT_IDLE: + case TaskPriority::LOWEST: + nPeriod = Scheduler::InfiniteTimeoutMs; + break; + default: + break; + } + } + + Task::StartTimer(nPeriod); +} + +sal_uInt64 Idle::UpdateMinPeriod( sal_uInt64 /* nTimeNow */ ) const +{ + return Scheduler::ImmediateTimeoutMs; +} + +AutoIdle::AutoIdle( const char *pDebugName ) + : Idle( true, pDebugName ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/salplug.cxx b/vcl/source/app/salplug.cxx new file mode 100644 index 000000000..1868853e9 --- /dev/null +++ b/vcl/source/app/salplug.cxx @@ -0,0 +1,355 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#include +#include + +#include +#else +#include +#include +#endif + +#include + +#ifdef ANDROID +#error "Android has no plugin infrastructure!" +#endif + +#if !(defined _WIN32 || defined MACOSX) +#define DESKTOPDETECT +#define HEADLESS_VCLPLUG +#endif + +extern "C" { +typedef SalInstance*(*salFactoryProc)(); +} + +namespace { + +oslModule pCloseModule = nullptr; + +SalInstance* tryInstance( const OUString& rModuleBase, bool bForce = false ) +{ +#ifdef HEADLESS_VCLPLUG + if (rModuleBase == "svp") + return svp_create_SalInstance(); +#endif + + SalInstance* pInst = nullptr; + OUString aUsedModuleBase(rModuleBase); + if (aUsedModuleBase == "kde5") + aUsedModuleBase = "kf5"; + OUString aModule( +#ifdef SAL_DLLPREFIX + SAL_DLLPREFIX +#endif + "vclplug_" + aUsedModuleBase + "lo" SAL_DLLEXTENSION ); + + osl::Module aMod; + if (aMod.loadRelative(reinterpret_cast(&tryInstance), aModule, SAL_LOADMODULE_GLOBAL)) + { + salFactoryProc aProc = reinterpret_cast(aMod.getFunctionSymbol("create_SalInstance")); + if (aProc) + { + pInst = aProc(); + SAL_INFO( + "vcl.plugadapt", + "sal plugin " << aModule << " produced instance " << pInst); + if (pInst) + { + pCloseModule = static_cast(aMod); + aMod.release(); + + /* + * 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( aUsedModuleBase == "gtk3" || aUsedModuleBase == "gtk3_kde5" || aUsedModuleBase == "win" ) + { + pCloseModule = nullptr; + } + } + } + else + { + SAL_WARN( + "vcl.plugadapt", + "could not load symbol create_SalInstance from shared object " + << aModule); + } + } + else if (bForce) + { + SAL_WARN("vcl.plugadapt", "could not load shared object " << aModule); + } + else + { + SAL_INFO("vcl.plugadapt", "could not load shared object " << aModule); + } + + // coverity[leaked_storage] - this is on purpose + return pInst; +} + +#ifdef DESKTOPDETECT +extern "C" typedef DesktopType Fn_get_desktop_environment(); + +DesktopType get_desktop_environment() +{ + OUString aModule(DESKTOP_DETECTOR_DLL_NAME); + oslModule aMod = osl_loadModuleRelative( + reinterpret_cast< oslGenericFunction >( &tryInstance ), aModule.pData, + SAL_LOADMODULE_DEFAULT ); + DesktopType ret = DESKTOP_UNKNOWN; + if( aMod ) + { + Fn_get_desktop_environment * pSym + = reinterpret_cast( + osl_getAsciiFunctionSymbol(aMod, "get_desktop_environment")); + if( pSym ) + ret = pSym(); + } + osl_unloadModule( aMod ); + return ret; +} + +SalInstance* autodetect_plugin() +{ + static const char* const pKDEFallbackList[] = + { +#if ENABLE_KF5 + "kf5", +#endif +#if ENABLE_GTK3_KDE5 + "gtk3_kde5", +#endif + "gtk3", "gen", nullptr + }; + + static const char* const pStandardFallbackList[] = + { + "gtk3", "gen", nullptr + }; + +#ifdef HEADLESS_VCLPLUG + static const char* const pHeadlessFallbackList[] = + { + "svp", nullptr + }; +#endif + + DesktopType desktop = get_desktop_environment(); + const char * const * pList = pStandardFallbackList; + int nListEntry = 0; + +#ifdef HEADLESS_VCLPLUG + // no server at all: dummy plugin + if ( desktop == DESKTOP_NONE ) + pList = pHeadlessFallbackList; + else +#endif + if ( desktop == DESKTOP_GNOME || + desktop == DESKTOP_UNITY || + desktop == DESKTOP_XFCE || + desktop == DESKTOP_MATE ) + pList = pStandardFallbackList; + else if (desktop == DESKTOP_PLASMA5 || desktop == DESKTOP_LXQT) + pList = pKDEFallbackList; + + SalInstance* pInst = nullptr; + while( pList[nListEntry] && pInst == nullptr ) + { + OUString aTry( OUString::createFromAscii( pList[nListEntry] ) ); + pInst = tryInstance( aTry ); + SAL_INFO_IF( + pInst, "vcl.plugadapt", + "plugin autodetection: " << pList[nListEntry]); + nListEntry++; + } + + return pInst; +} +#endif // DESKTOPDETECT + +#ifdef HEADLESS_VCLPLUG +// HACK to obtain Application::IsHeadlessModeEnabled early on, before +// Application::EnableHeadlessMode has potentially been called: +bool IsHeadlessModeRequested() +{ + if (Application::IsHeadlessModeEnabled()) { + return true; + } + sal_uInt32 n = rtl_getAppCommandArgCount(); + for (sal_uInt32 i = 0; i < n; ++i) { + OUString arg; + rtl_getAppCommandArg(i, &arg.pData); + if ( arg == "--headless" || arg == "-headless" ) { + return true; + } + } + return false; +} +#endif + +} // anonymous namespace + +SalInstance *CreateSalInstance() +{ + SalInstance *pInst = nullptr; + + OUString aUsePlugin; + rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", aUsePlugin); + SAL_INFO_IF(!aUsePlugin.isEmpty(), "vcl", "Requested VCL plugin: " << aUsePlugin); +#ifdef HEADLESS_VCLPLUG + if (Application::IsBitmapRendering() || (aUsePlugin.isEmpty() && IsHeadlessModeRequested())) + aUsePlugin = "svp"; +#endif + + if (aUsePlugin == "svp") + { + Application::EnableBitmapRendering(); +#ifndef HEADLESS_VCLPLUG + aUsePlugin.clear(); +#endif + } + if( !aUsePlugin.isEmpty() ) + pInst = tryInstance( aUsePlugin, true ); + +#ifdef DESKTOPDETECT + if( ! pInst ) + pInst = autodetect_plugin(); +#endif + + // fallback, try everything + static const char* const pPlugin[] = { +#ifdef _WIN32 + "win" +#else +#ifdef MACOSX + "osx" +#else + "gtk3", "kf5", "gen" +#endif +#endif + }; + + for ( int i = 0; !pInst && i != SAL_N_ELEMENTS(pPlugin); ++i ) + pInst = tryInstance( OUString::createFromAscii( pPlugin[ i ] ) ); + + if( ! pInst ) + { + std::fprintf( stderr, "no suitable windowing system found, exiting.\n" ); + _exit( 1 ); + } + + // acquire SolarMutex + pInst->AcquireYieldMutex(); + + return pInst; +} + +void DestroySalInstance( SalInstance *pInst ) +{ + // release SolarMutex + pInst->ReleaseYieldMutexAll(); + + delete pInst; + if( pCloseModule ) + osl_unloadModule( pCloseModule ); +} + +void SalAbort( const OUString& rErrorText, bool bDumpCore ) +{ + if( rErrorText.isEmpty() ) + std::fprintf( stderr, "Application Error\n" ); + else + { + CrashReporter::addKeyValue("AbortMessage", rErrorText, CrashReporter::Write); + std::fprintf( stderr, "%s\n", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() ); + } + if( bDumpCore ) + abort(); + else + _exit(1); +} + +const OUString& SalGetDesktopEnvironment() +{ +#ifdef _WIN32 + static OUString aDesktopEnvironment( "Windows" ); + +#else +#ifdef MACOSX + static OUString aDesktopEnvironment( "MacOSX" ); +#else + // Order to match desktops.hxx' DesktopType + static const char * const desktop_strings[] = { + "none", "unknown", "GNOME", "UNITY", + "XFCE", "MATE", "PLASMA5", "LXQT" }; + static OUString aDesktopEnvironment; + if( aDesktopEnvironment.isEmpty()) + { + aDesktopEnvironment = OUString::createFromAscii( + desktop_strings[get_desktop_environment()]); + } +#endif +#endif + return aDesktopEnvironment; +} + +SalData::SalData() : + m_pInstance(nullptr), + m_pPIManager(nullptr) +{ +} + +SalData::~SalData() COVERITY_NOEXCEPT_FALSE +{ +#if (defined UNX && !defined MACOSX) + psp::PrinterInfoManager::release(); +#endif +} + +#ifdef _WIN32 +bool HasAtHook() +{ + BOOL bIsRunning = FALSE; + // pvParam must be BOOL + return SystemParametersInfoW(SPI_GETSCREENREADER, 0, &bIsRunning, 0) + && bIsRunning; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/salusereventlist.cxx b/vcl/source/app/salusereventlist.cxx new file mode 100644 index 000000000..088bc141f --- /dev/null +++ b/vcl/source/app/salusereventlist.cxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +SalUserEventList::SalUserEventList() + : m_bAllUserEventProcessedSignaled( true ) + , m_aProcessingThread(0) +{ +} + +SalUserEventList::~SalUserEventList() COVERITY_NOEXCEPT_FALSE +{ +} + +void SalUserEventList::insertFrame( SalFrame* pFrame ) +{ + auto aPair = m_aFrames.insert( pFrame ); + assert( aPair.second ); (void) aPair; +} + +void SalUserEventList::eraseFrame( SalFrame* pFrame ) +{ + auto it = m_aFrames.find( pFrame ); + assert( it != m_aFrames.end() ); + if ( it != m_aFrames.end() ) + m_aFrames.erase( it ); +} + +bool SalUserEventList::DispatchUserEvents( bool bHandleAllCurrentEvents ) +{ + bool bWasEvent = false; + oslThreadIdentifier aCurId = osl::Thread::getCurrentIdentifier(); + + DBG_TESTSOLARMUTEX(); + osl::ResettableMutexGuard aResettableListGuard(m_aUserEventsMutex); + + if (!m_aUserEvents.empty()) + { + if (bHandleAllCurrentEvents) + { + if (m_aProcessingUserEvents.empty()) + m_aProcessingUserEvents.swap(m_aUserEvents); + else + m_aProcessingUserEvents.splice(m_aProcessingUserEvents.end(), m_aUserEvents); + } + else if (m_aProcessingUserEvents.empty()) + { + m_aProcessingUserEvents.push_back( m_aUserEvents.front() ); + m_aUserEvents.pop_front(); + } + } + + if (HasUserEvents()) + { + bWasEvent = true; + m_aProcessingThread = aCurId; + + SalUserEvent aEvent( nullptr, nullptr, SalEvent::NONE ); + do { + if (m_aProcessingUserEvents.empty() || aCurId != m_aProcessingThread) + break; + aEvent = m_aProcessingUserEvents.front(); + m_aProcessingUserEvents.pop_front(); + + // remember to reset the guard before break or continue the loop + aResettableListGuard.clear(); + + if ( !isFrameAlive( aEvent.m_pFrame ) ) + { + if ( aEvent.m_nEvent == SalEvent::UserEvent ) + delete static_cast< ImplSVEvent* >( aEvent.m_pData ); + aResettableListGuard.reset(); + continue; + } + +#ifndef IOS + try +#endif + { + ProcessEvent( aEvent ); + } +#ifndef IOS + catch (css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("vcl", "Uncaught"); + std::abort(); + } + catch (std::exception& e) + { + SAL_WARN("vcl", "Uncaught " << typeid(e).name() << " " << e.what()); + std::abort(); + } + catch (...) + { + SAL_WARN("vcl", "Uncaught exception during DispatchUserEvents!"); + std::abort(); + } +#endif + aResettableListGuard.reset(); + if (!bHandleAllCurrentEvents) + break; + } + while( true ); + } + + if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents() ) + { + m_bAllUserEventProcessedSignaled = true; + TriggerAllUserEventsProcessed(); + } + + return bWasEvent; +} + +void SalUserEventList::RemoveEvent( SalFrame* pFrame, void* pData, SalEvent nEvent ) +{ + SalUserEvent aEvent( pFrame, pData, nEvent ); + + osl::MutexGuard aGuard( m_aUserEventsMutex ); + auto it = std::find( m_aUserEvents.begin(), m_aUserEvents.end(), aEvent ); + if ( it != m_aUserEvents.end() ) + { + m_aUserEvents.erase( it ); + } + else + { + it = std::find( m_aProcessingUserEvents.begin(), m_aProcessingUserEvents.end(), aEvent ); + if ( it != m_aProcessingUserEvents.end() ) + { + m_aProcessingUserEvents.erase( it ); + } + } + + if ( !m_bAllUserEventProcessedSignaled && !HasUserEvents() ) + { + m_bAllUserEventProcessedSignaled = true; + TriggerAllUserEventsProcessed(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx new file mode 100644 index 000000000..d7c93164a --- /dev/null +++ b/vcl/source/app/salvtables.cxx @@ -0,0 +1,6777 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +SalFrame::SalFrame() + : m_pWindow(nullptr) + , m_pProc(nullptr) +{ +} + +// this file contains the virtual destructors of the sal interface +// compilers usually put their vtables where the destructor is + +SalFrame::~SalFrame() {} + +void SalFrame::SetCallback(vcl::Window* pWindow, SALFRAMEPROC pProc) +{ + m_pWindow = pWindow; + m_pProc = pProc; +} + +// default to full-frame flushes +// on ports where partial-flushes are much cheaper this method should be overridden +void SalFrame::Flush(const tools::Rectangle&) { Flush(); } + +void SalFrame::SetRepresentedURL(const OUString&) +{ + // currently this is Mac only functionality +} + +SalInstance::SalInstance(std::unique_ptr pMutex) + : m_pYieldMutex(std::move(pMutex)) +{ +} + +SalInstance::~SalInstance() {} + +comphelper::SolarMutex* SalInstance::GetYieldMutex() { return m_pYieldMutex.get(); } + +sal_uInt32 SalInstance::ReleaseYieldMutexAll() { return m_pYieldMutex->release(true); } + +void SalInstance::AcquireYieldMutex(sal_uInt32 nCount) { m_pYieldMutex->acquire(nCount); } + +std::unique_ptr SalInstance::CreateSalSession() { return nullptr; } + +std::unique_ptr SalInstance::CreateMenu(bool, Menu*) +{ + // default: no native menus + return nullptr; +} + +std::unique_ptr SalInstance::CreateMenuItem(const SalItemParams&) { return nullptr; } + +bool SalInstance::CallEventCallback(void const* pEvent, int nBytes) +{ + return m_pEventInst.is() && m_pEventInst->dispatchEvent(pEvent, nBytes); +} + +SalTimer::~SalTimer() COVERITY_NOEXCEPT_FALSE {} + +void SalBitmap::DropScaledCache() +{ + if (ImplSVData* pSVData = ImplGetSVData()) + { + auto& rCache = pSVData->maGDIData.maScaleCache; + + rCache.remove_if([this] (const lru_scale_cache::key_value_pair_t& rKeyValuePair) + { return rKeyValuePair.first.mpBitmap == this; }); + } +} + +SalBitmap::~SalBitmap() { DropScaledCache(); } + +SalSystem::~SalSystem() {} + +SalPrinter::~SalPrinter() {} + +bool SalPrinter::StartJob(const OUString*, const OUString&, const OUString&, ImplJobSetup*, + vcl::PrinterController&) +{ + return false; +} + +SalInfoPrinter::~SalInfoPrinter() {} + +SalVirtualDevice::~SalVirtualDevice() {} + +SalObject::~SalObject() {} + +SalMenu::~SalMenu() {} + +bool SalMenu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&, FloatWinPopupFlags) +{ + return false; +} + +void SalMenu::ShowCloseButton(bool) {} + +bool SalMenu::AddMenuBarButton(const SalMenuButtonItem&) { return false; } + +void SalMenu::RemoveMenuBarButton(sal_uInt16) {} + +tools::Rectangle SalMenu::GetMenuBarButtonRectPixel(sal_uInt16, SalFrame*) +{ + return tools::Rectangle(); +} + +int SalMenu::GetMenuBarHeight() const { return 0; } + +void SalMenu::ApplyPersona() {} + +SalMenuItem::~SalMenuItem() {} + +void SalInstanceWidget::ensure_event_listener() +{ + if (!m_bEventListener) + { + m_xWidget->AddEventListener(LINK(this, SalInstanceWidget, EventListener)); + m_bEventListener = true; + } +} + +// we want the ability to mark key events as handled, so use this variant +// for those, we get all keystrokes in this case, so we will need to filter +// them later +void SalInstanceWidget::ensure_key_listener() +{ + if (!m_bKeyEventListener) + { + Application::AddKeyListener(LINK(this, SalInstanceWidget, KeyEventListener)); + m_bKeyEventListener = true; + } +} + +// we want the ability to know about mouse events that happen in our children +// so use this variant, we will need to filter them later +void SalInstanceWidget::ensure_mouse_listener() +{ + if (!m_bMouseEventListener) + { + Application::AddEventListener(LINK(this, SalInstanceWidget, MouseEventListener)); + m_bMouseEventListener = true; + } +} + +void SalInstanceWidget::set_background(const Color& rColor) +{ + m_xWidget->SetControlBackground(rColor); + m_xWidget->SetBackground(m_xWidget->GetControlBackground()); + // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under" + // transparent children of the widget + m_xWidget->SetStyle(m_xWidget->GetStyle() & ~WB_CLIPCHILDREN); +} + +SalInstanceWidget::SalInstanceWidget(vcl::Window* pWidget, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : m_xWidget(pWidget) + , m_pBuilder(pBuilder) + , m_bTakeOwnership(bTakeOwnership) + , m_bEventListener(false) + , m_bKeyEventListener(false) + , m_bMouseEventListener(false) + , m_nBlockNotify(0) +{ +} + +void SalInstanceWidget::set_sensitive(bool sensitive) { m_xWidget->Enable(sensitive); } + +bool SalInstanceWidget::get_sensitive() const { return m_xWidget->IsEnabled(); } + +bool SalInstanceWidget::get_visible() const { return m_xWidget->IsVisible(); } + +bool SalInstanceWidget::is_visible() const { return m_xWidget->IsReallyVisible(); } + +void SalInstanceWidget::set_can_focus(bool bCanFocus) +{ + auto nStyle = m_xWidget->GetStyle() & ~(WB_TABSTOP | WB_NOTABSTOP); + if (bCanFocus) + nStyle |= WB_TABSTOP; + else + nStyle |= WB_NOTABSTOP; + m_xWidget->SetStyle(nStyle); +} + +void SalInstanceWidget::grab_focus() { m_xWidget->GrabFocus(); } + +bool SalInstanceWidget::has_focus() const { return m_xWidget->HasFocus(); } + +bool SalInstanceWidget::is_active() const { return m_xWidget->IsActive(); } + +void SalInstanceWidget::set_has_default(bool has_default) +{ + m_xWidget->set_property("has-default", OUString::boolean(has_default)); +} + +bool SalInstanceWidget::get_has_default() const { return m_xWidget->GetStyle() & WB_DEFBUTTON; } + +void SalInstanceWidget::show() { m_xWidget->Show(); } + +void SalInstanceWidget::hide() { m_xWidget->Hide(); } + +void SalInstanceWidget::set_size_request(int nWidth, int nHeight) +{ + m_xWidget->set_width_request(nWidth); + m_xWidget->set_height_request(nHeight); +} + +Size SalInstanceWidget::get_size_request() const +{ + return Size(m_xWidget->get_width_request(), m_xWidget->get_height_request()); +} + +Size SalInstanceWidget::get_preferred_size() const { return m_xWidget->get_preferred_size(); } + +float SalInstanceWidget::get_approximate_digit_width() const +{ + return m_xWidget->approximate_digit_width(); +} + +int SalInstanceWidget::get_text_height() const { return m_xWidget->GetTextHeight(); } + +Size SalInstanceWidget::get_pixel_size(const OUString& rText) const +{ + //TODO, or do I want GetTextBoundRect ?, just using width at the moment anyway + return Size(m_xWidget->GetTextWidth(rText), m_xWidget->GetTextHeight()); +} + +vcl::Font SalInstanceWidget::get_font() { return m_xWidget->GetPointFont(*m_xWidget); } + +OString SalInstanceWidget::get_buildable_name() const { return m_xWidget->get_id().toUtf8(); } + +void SalInstanceWidget::set_help_id(const OString& rId) { return m_xWidget->SetHelpId(rId); } + +OString SalInstanceWidget::get_help_id() const { return m_xWidget->GetHelpId(); } + +void SalInstanceWidget::set_grid_left_attach(int nAttach) +{ + m_xWidget->set_grid_left_attach(nAttach); +} + +int SalInstanceWidget::get_grid_left_attach() const { return m_xWidget->get_grid_left_attach(); } + +void SalInstanceWidget::set_grid_width(int nCols) { m_xWidget->set_grid_width(nCols); } + +void SalInstanceWidget::set_grid_top_attach(int nAttach) +{ + m_xWidget->set_grid_top_attach(nAttach); +} + +int SalInstanceWidget::get_grid_top_attach() const { return m_xWidget->get_grid_top_attach(); } + +void SalInstanceWidget::set_hexpand(bool bExpand) { m_xWidget->set_hexpand(bExpand); } + +bool SalInstanceWidget::get_hexpand() const { return m_xWidget->get_hexpand(); } + +void SalInstanceWidget::set_vexpand(bool bExpand) { m_xWidget->set_vexpand(bExpand); } + +bool SalInstanceWidget::get_vexpand() const { return m_xWidget->get_vexpand(); } + +void SalInstanceWidget::set_secondary(bool bSecondary) { m_xWidget->set_secondary(bSecondary); } + +void SalInstanceWidget::set_margin_top(int nMargin) { m_xWidget->set_margin_top(nMargin); } + +void SalInstanceWidget::set_margin_bottom(int nMargin) { m_xWidget->set_margin_bottom(nMargin); } + +void SalInstanceWidget::set_margin_left(int nMargin) { m_xWidget->set_margin_left(nMargin); } + +void SalInstanceWidget::set_margin_right(int nMargin) { m_xWidget->set_margin_bottom(nMargin); } + +int SalInstanceWidget::get_margin_top() const { return m_xWidget->get_margin_top(); } + +int SalInstanceWidget::get_margin_bottom() const { return m_xWidget->get_margin_bottom(); } + +int SalInstanceWidget::get_margin_left() const { return m_xWidget->get_margin_left(); } + +int SalInstanceWidget::get_margin_right() const { return m_xWidget->get_margin_bottom(); } + +void SalInstanceWidget::set_accessible_name(const OUString& rName) +{ + m_xWidget->SetAccessibleName(rName); +} + +OUString SalInstanceWidget::get_accessible_name() const { return m_xWidget->GetAccessibleName(); } + +OUString SalInstanceWidget::get_accessible_description() const +{ + return m_xWidget->GetAccessibleDescription(); +} + +void SalInstanceWidget::set_accessible_relation_labeled_by(weld::Widget* pLabel) +{ + vcl::Window* pAtkLabel + = pLabel ? dynamic_cast(*pLabel).getWidget() : nullptr; + m_xWidget->SetAccessibleRelationLabeledBy(pAtkLabel); +} + +void SalInstanceWidget::set_accessible_relation_label_for(weld::Widget* pLabeled) +{ + vcl::Window* pAtkLabeled + = pLabeled ? dynamic_cast(*pLabeled).getWidget() : nullptr; + m_xWidget->SetAccessibleRelationLabelFor(pAtkLabeled); +} + +void SalInstanceWidget::set_tooltip_text(const OUString& rTip) +{ + m_xWidget->SetQuickHelpText(rTip); +} + +OUString SalInstanceWidget::get_tooltip_text() const { return m_xWidget->GetQuickHelpText(); } + +void SalInstanceWidget::connect_focus_in(const Link& rLink) +{ + ensure_event_listener(); + weld::Widget::connect_focus_in(rLink); +} + +void SalInstanceWidget::connect_mnemonic_activate(const Link& rLink) +{ + m_xWidget->SetMnemonicActivateHdl(LINK(this, SalInstanceWidget, MnemonicActivateHdl)); + weld::Widget::connect_mnemonic_activate(rLink); +} + +void SalInstanceWidget::connect_focus_out(const Link& rLink) +{ + ensure_event_listener(); + weld::Widget::connect_focus_out(rLink); +} + +void SalInstanceWidget::connect_size_allocate(const Link& rLink) +{ + ensure_event_listener(); + weld::Widget::connect_size_allocate(rLink); +} + +void SalInstanceWidget::connect_mouse_press(const Link& rLink) +{ + ensure_mouse_listener(); + weld::Widget::connect_mouse_press(rLink); +} + +void SalInstanceWidget::connect_mouse_move(const Link& rLink) +{ + ensure_mouse_listener(); + weld::Widget::connect_mouse_move(rLink); +} + +void SalInstanceWidget::connect_mouse_release(const Link& rLink) +{ + ensure_mouse_listener(); + weld::Widget::connect_mouse_release(rLink); +} + +void SalInstanceWidget::connect_key_press(const Link& rLink) +{ + ensure_key_listener(); + weld::Widget::connect_key_press(rLink); +} + +void SalInstanceWidget::connect_key_release(const Link& rLink) +{ + ensure_key_listener(); + weld::Widget::connect_key_release(rLink); +} + +bool SalInstanceWidget::get_extents_relative_to(Widget& rRelative, int& x, int& y, int& width, + int& height) +{ + tools::Rectangle aRect(m_xWidget->GetWindowExtentsRelative( + dynamic_cast(rRelative).getWidget())); + x = aRect.Left(); + y = aRect.Top(); + width = aRect.GetWidth(); + height = aRect.GetHeight(); + return true; +} + +void SalInstanceWidget::grab_add() { m_xWidget->CaptureMouse(); } + +bool SalInstanceWidget::has_grab() const { return m_xWidget->IsMouseCaptured(); } + +void SalInstanceWidget::grab_remove() { m_xWidget->ReleaseMouse(); } + +bool SalInstanceWidget::get_direction() const { return m_xWidget->IsRTLEnabled(); } + +void SalInstanceWidget::set_direction(bool bRTL) { m_xWidget->EnableRTL(bRTL); } + +void SalInstanceWidget::freeze() { m_xWidget->SetUpdateMode(false); } + +void SalInstanceWidget::thaw() { m_xWidget->SetUpdateMode(true); } + +SalInstanceWidget::~SalInstanceWidget() +{ + if (m_aMnemonicActivateHdl.IsSet()) + m_xWidget->SetMnemonicActivateHdl(Link()); + if (m_bMouseEventListener) + Application::RemoveEventListener(LINK(this, SalInstanceWidget, MouseEventListener)); + if (m_bKeyEventListener) + Application::RemoveKeyListener(LINK(this, SalInstanceWidget, KeyEventListener)); + if (m_bEventListener) + m_xWidget->RemoveEventListener(LINK(this, SalInstanceWidget, EventListener)); + if (m_bTakeOwnership) + m_xWidget.disposeAndClear(); +} + +vcl::Window* SalInstanceWidget::getWidget() { return m_xWidget; } + +void SalInstanceWidget::disable_notify_events() { ++m_nBlockNotify; } + +bool SalInstanceWidget::notify_events_disabled() { return m_nBlockNotify != 0; } + +void SalInstanceWidget::enable_notify_events() { --m_nBlockNotify; } + +OUString SalInstanceWidget::strip_mnemonic(const OUString& rLabel) const +{ + return rLabel.replaceFirst("~", ""); +} + +VclPtr SalInstanceWidget::create_virtual_device() const +{ + // create with (annoying) separate alpha layer that LibreOffice itself uses + return VclPtr::Create(*Application::GetDefaultDevice(), DeviceFormat::DEFAULT, + DeviceFormat::DEFAULT); +} + +css::uno::Reference SalInstanceWidget::get_drop_target() +{ + return m_xWidget->GetDropTarget(); +} + +void SalInstanceWidget::connect_get_property_tree( + const Link& rLink) +{ + m_xWidget->SetDumpAsPropertyTreeHdl(rLink); +} + +void SalInstanceWidget::set_stack_background() +{ + set_background(m_xWidget->GetSettings().GetStyleSettings().GetWindowColor()); +} + +void SalInstanceWidget::set_toolbar_background() +{ + m_xWidget->SetBackground(); + m_xWidget->SetPaintTransparent(true); +} + +void SalInstanceWidget::set_highlight_background() +{ + set_background(m_xWidget->GetSettings().GetStyleSettings().GetHighlightColor()); +} + +SystemWindow* SalInstanceWidget::getSystemWindow() { return m_xWidget->GetSystemWindow(); } + +void SalInstanceWidget::HandleEventListener(VclWindowEvent& rEvent) +{ + if (rEvent.GetId() == VclEventId::WindowGetFocus) + m_aFocusInHdl.Call(*this); + else if (rEvent.GetId() == VclEventId::WindowLoseFocus) + m_aFocusOutHdl.Call(*this); + else if (rEvent.GetId() == VclEventId::WindowResize) + m_aSizeAllocateHdl.Call(m_xWidget->GetSizePixel()); +} + +void SalInstanceWidget::HandleMouseEventListener(VclSimpleEvent& rEvent) +{ + if (rEvent.GetId() == VclEventId::WindowMouseButtonDown) + { + auto& rWinEvent = static_cast(rEvent); + if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow())) + { + const MouseEvent* pMouseEvent = static_cast(rWinEvent.GetData()); + m_aMousePressHdl.Call(*pMouseEvent); + } + } + else if (rEvent.GetId() == VclEventId::WindowMouseButtonUp) + { + auto& rWinEvent = static_cast(rEvent); + if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow())) + { + const MouseEvent* pMouseEvent = static_cast(rWinEvent.GetData()); + m_aMouseReleaseHdl.Call(*pMouseEvent); + } + } + else if (rEvent.GetId() == VclEventId::WindowMouseMove) + { + auto& rWinEvent = static_cast(rEvent); + if (m_xWidget->IsWindowOrChild(rWinEvent.GetWindow())) + { + const MouseEvent* pMouseEvent = static_cast(rWinEvent.GetData()); + m_aMouseMotionHdl.Call(*pMouseEvent); + } + } +} + +bool SalInstanceWidget::HandleKeyEventListener(VclWindowEvent& rEvent) +{ + // we get all key events here, ignore them unless we have focus + if (!has_focus()) + return false; + if (rEvent.GetId() == VclEventId::WindowKeyInput) + { + const KeyEvent* pKeyEvent = static_cast(rEvent.GetData()); + return m_aKeyPressHdl.Call(*pKeyEvent); + } + else if (rEvent.GetId() == VclEventId::WindowKeyUp) + { + const KeyEvent* pKeyEvent = static_cast(rEvent.GetData()); + return m_aKeyReleaseHdl.Call(*pKeyEvent); + } + return false; +} + +IMPL_LINK(SalInstanceWidget, EventListener, VclWindowEvent&, rEvent, void) +{ + HandleEventListener(rEvent); +} + +IMPL_LINK(SalInstanceWidget, KeyEventListener, VclWindowEvent&, rEvent, bool) +{ + return HandleKeyEventListener(rEvent); +} + +IMPL_LINK(SalInstanceWidget, MouseEventListener, VclSimpleEvent&, rEvent, void) +{ + HandleMouseEventListener(rEvent); +} + +IMPL_LINK_NOARG(SalInstanceWidget, MnemonicActivateHdl, vcl::Window&, bool) +{ + return m_aMnemonicActivateHdl.Call(*this); +} + +namespace +{ +Image createImage(const OUString& rImage) +{ + if (rImage.isEmpty()) + return Image(); + if (rImage.lastIndexOf('.') != rImage.getLength() - 4) + { + assert((rImage == "dialog-warning" || rImage == "dialog-error" + || rImage == "dialog-information") + && "unknown stock image"); + if (rImage == "dialog-warning") + return Image(StockImage::Yes, IMG_WARN); + else if (rImage == "dialog-error") + return Image(StockImage::Yes, IMG_ERROR); + else if (rImage == "dialog-information") + return Image(StockImage::Yes, IMG_INFO); + } + return Image(StockImage::Yes, rImage); +} + +Image createImage(const VirtualDevice& rDevice) +{ + return Image(rDevice.GetBitmapEx(Point(), rDevice.GetOutputSizePixel())); +} + +sal_uInt16 insert_to_menu(sal_uInt16 nLastId, PopupMenu* pMenu, int pos, const OUString& rId, + const OUString& rStr, const OUString* pIconName, + const VirtualDevice* pImageSurface, TriState eCheckRadioFalse) +{ + const sal_uInt16 nNewid = nLastId + 1; + + MenuItemBits nBits; + if (eCheckRadioFalse == TRISTATE_TRUE) + nBits = MenuItemBits::CHECKABLE; + else if (eCheckRadioFalse == TRISTATE_FALSE) + nBits = MenuItemBits::CHECKABLE | MenuItemBits::RADIOCHECK; + else + nBits = MenuItemBits::NONE; + + pMenu->InsertItem(nNewid, rStr, nBits, + OUStringToOString(rId, RTL_TEXTENCODING_UTF8), pos == -1 ? MENU_APPEND : pos); + if (pIconName) + { + pMenu->SetItemImage(nNewid, createImage(*pIconName)); + } + else if (pImageSurface) + { + pMenu->SetItemImage(nNewid, createImage(*pImageSurface)); + } + return nNewid; +} +} + +SalInstanceMenu::SalInstanceMenu(PopupMenu* pMenu, bool bTakeOwnership) + : m_xMenu(pMenu) + , m_bTakeOwnership(bTakeOwnership) +{ + const auto nCount = m_xMenu->GetItemCount(); + m_nLastId = nCount ? pMenu->GetItemId(nCount - 1) : 0; + m_xMenu->SetSelectHdl(LINK(this, SalInstanceMenu, SelectMenuHdl)); +} +OString SalInstanceMenu::popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect) +{ + SalInstanceWidget* pVclWidget = dynamic_cast(pParent); + assert(pVclWidget); + m_xMenu->Execute(pVclWidget->getWidget(), rRect, + PopupMenuFlags::ExecuteDown | PopupMenuFlags::NoMouseUpClose); + return m_xMenu->GetCurItemIdent(); +} +void SalInstanceMenu::set_sensitive(const OString& rIdent, bool bSensitive) +{ + m_xMenu->EnableItem(rIdent, bSensitive); +} +void SalInstanceMenu::set_active(const OString& rIdent, bool bActive) +{ + m_xMenu->CheckItem(rIdent, bActive); +} +bool SalInstanceMenu::get_active(const OString& rIdent) const +{ + return m_xMenu->IsItemChecked(m_xMenu->GetItemId(rIdent)); +} +void SalInstanceMenu::set_label(const OString& rIdent, const OUString& rLabel) +{ + m_xMenu->SetItemText(m_xMenu->GetItemId(rIdent), rLabel); +} +OUString SalInstanceMenu::get_label(const OString& rIdent) const +{ + return m_xMenu->GetItemText(m_xMenu->GetItemId(rIdent)); +} +void SalInstanceMenu::set_visible(const OString& rIdent, bool bShow) +{ + m_xMenu->ShowItem(m_xMenu->GetItemId(rIdent), bShow); +} +void SalInstanceMenu::clear() { m_xMenu->Clear(); } +void SalInstanceMenu::insert(int pos, const OUString& rId, const OUString& rStr, + const OUString* pIconName, VirtualDevice* pImageSurface, + TriState eCheckRadioFalse) +{ + m_nLastId + = insert_to_menu(m_nLastId, m_xMenu, pos, rId, rStr, pIconName, pImageSurface, eCheckRadioFalse); +} +void SalInstanceMenu::insert_separator(int pos, const OUString& rId) +{ + auto nInsertPos = pos == -1 ? MENU_APPEND : pos; + m_xMenu->InsertSeparator(rId.toUtf8(), nInsertPos); +} +void SalInstanceMenu::remove(const OString& rId) +{ + m_xMenu->RemoveItem(m_xMenu->GetItemPos(m_xMenu->GetItemId(rId))); +} +int SalInstanceMenu::n_children() const { return m_xMenu->GetItemCount(); } +PopupMenu* SalInstanceMenu::getMenu() const { return m_xMenu.get(); } +SalInstanceMenu::~SalInstanceMenu() +{ + m_xMenu->SetSelectHdl(Link<::Menu*, bool>()); + if (m_bTakeOwnership) + m_xMenu.disposeAndClear(); +} + +IMPL_LINK_NOARG(SalInstanceMenu, SelectMenuHdl, ::Menu*, bool) +{ + signal_activate(m_xMenu->GetCurItemIdent()); + /* tdf#131333 Menu::Select depends on a false here to allow + propagating a submens's selected id to its parent menu to become its + selected id. + + without this, while gen menus already have propagated this to its parent + in MenuFloatingWindow::EndExecute, SalMenus as used under kf5/macOS + won't propagate the selected id + */ + return false; +} + +namespace +{ +class SalInstanceToolbar : public SalInstanceWidget, public virtual weld::Toolbar +{ +private: + VclPtr m_xToolBox; + std::map> m_aFloats; + std::map> m_aMenus; + + OString m_sStartShowIdent; + + DECL_LINK(ClickHdl, ToolBox*, void); + DECL_LINK(DropdownClick, ToolBox*, void); + DECL_LINK(MenuToggleListener, VclWindowEvent&, void); + +public: + SalInstanceToolbar(ToolBox* pToolBox, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pToolBox, pBuilder, bTakeOwnership) + , m_xToolBox(pToolBox) + { + m_xToolBox->SetSelectHdl(LINK(this, SalInstanceToolbar, ClickHdl)); + m_xToolBox->SetDropdownClickHdl(LINK(this, SalInstanceToolbar, DropdownClick)); + } + + virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override + { + m_xToolBox->EnableItem(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), bSensitive); + } + + virtual bool get_item_sensitive(const OString& rIdent) const override + { + return m_xToolBox->IsItemEnabled(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent))); + } + + virtual void set_item_visible(const OString& rIdent, bool bVisible) override + { + m_xToolBox->ShowItem(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), bVisible); + } + + virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override + { + m_xToolBox->SetHelpId(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rHelpId); + } + + virtual bool get_item_visible(const OString& rIdent) const override + { + return m_xToolBox->IsItemVisible(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent))); + } + + virtual void set_item_active(const OString& rIdent, bool bActive) override + { + sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + m_xToolBox->CheckItem(nItemId, bActive); + } + + virtual bool get_item_active(const OString& rIdent) const override + { + return m_xToolBox->IsItemChecked(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent))); + } + + void set_menu_item_active(const OString& rIdent, bool bActive) override + { + sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + assert(m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN); + + if (bActive) + { + m_sStartShowIdent = m_xToolBox->GetItemCommand(nItemId).toUtf8(); + signal_toggle_menu(m_sStartShowIdent); + } + + auto pFloat = m_aFloats[nItemId]; + if (pFloat) + { + if (bActive) + vcl::Window::GetDockingManager()->StartPopupMode(m_xToolBox, pFloat, + FloatWinPopupFlags::GrabFocus); + else + vcl::Window::GetDockingManager()->EndPopupMode(pFloat); + } + auto pPopup = m_aMenus[nItemId]; + if (pPopup) + { + if (bActive) + { + tools::Rectangle aRect = m_xToolBox->GetItemRect(nItemId); + pPopup->Execute(m_xToolBox, aRect, PopupMenuFlags::ExecuteDown); + } + else + pPopup->EndExecute(); + } + + m_sStartShowIdent.clear(); + } + + bool get_menu_item_active(const OString& rIdent) const override + { + sal_uInt16 nItemId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + assert(m_xToolBox->GetItemBits(nItemId) & ToolBoxItemBits::DROPDOWN); + + if (rIdent == m_sStartShowIdent) + return true; + + auto aFloat = m_aFloats.find(nItemId); + if (aFloat != m_aFloats.end()) + { + return vcl::Window::GetDockingManager()->IsInPopupMode(aFloat->second); + } + + auto aPopup = m_aMenus.find(nItemId); + if (aPopup != m_aMenus.end()) + { + return PopupMenu::GetActivePopupMenu() == aPopup->second; + } + + return false; + } + + virtual void set_item_popover(const OString& rIdent, weld::Widget* pPopover) override + { + SalInstanceWidget* pPopoverWidget = dynamic_cast(pPopover); + + vcl::Window* pFloat = pPopoverWidget ? pPopoverWidget->getWidget() : nullptr; + if (pFloat) + { + pFloat->AddEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener)); + pFloat->EnableDocking(); + } + + sal_uInt16 nId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + auto xOldFloat = m_aFloats[nId]; + if (xOldFloat) + { + xOldFloat->RemoveEventListener(LINK(this, SalInstanceToolbar, MenuToggleListener)); + } + m_aFloats[nId] = pFloat; + m_aMenus[nId] = nullptr; + } + + virtual void set_item_menu(const OString& rIdent, weld::Menu* pMenu) override + { + SalInstanceMenu* pInstanceMenu = dynamic_cast(pMenu); + + PopupMenu* pPopup = pInstanceMenu ? pInstanceMenu->getMenu() : nullptr; + + sal_uInt16 nId = m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)); + m_aMenus[nId] = pPopup; + m_aFloats[nId] = nullptr; + } + + virtual void insert_separator(int pos, const OUString& /*rId*/) override + { + auto nInsertPos = pos == -1 ? ToolBox::APPEND : pos; + m_xToolBox->InsertSeparator(nInsertPos, 5); + } + + virtual int get_n_items() const override { return m_xToolBox->GetItemCount(); } + + virtual OString get_item_ident(int nIndex) const override + { + return m_xToolBox->GetItemCommand(m_xToolBox->GetItemId(nIndex)).toUtf8(); + } + + virtual void set_item_ident(int nIndex, const OString& rIdent) override + { + return m_xToolBox->SetItemCommand(m_xToolBox->GetItemId(nIndex), + OUString::fromUtf8(rIdent)); + } + + virtual void set_item_label(int nIndex, const OUString& rLabel) override + { + m_xToolBox->SetItemText(m_xToolBox->GetItemId(nIndex), rLabel); + } + + virtual OUString get_item_label(const OString& rIdent) const override + { + return m_xToolBox->GetItemText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent))); + } + + virtual void set_item_label(const OString& rIdent, const OUString& rLabel) override + { + m_xToolBox->SetItemText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rLabel); + } + + virtual void set_item_icon_name(const OString& rIdent, const OUString& rIconName) override + { + m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), + Image(StockImage::Yes, rIconName)); + } + + virtual void set_item_image(const OString& rIdent, + const css::uno::Reference& rIcon) override + { + m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), Image(rIcon)); + } + + virtual void set_item_image(const OString& rIdent, VirtualDevice* pDevice) override + { + if (pDevice) + m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), + createImage(*pDevice)); + else + m_xToolBox->SetItemImage(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), Image()); + } + + virtual void set_item_image(int nIndex, + const css::uno::Reference& rIcon) override + { + m_xToolBox->SetItemImage(m_xToolBox->GetItemId(nIndex), Image(rIcon)); + } + + virtual void set_item_tooltip_text(int nIndex, const OUString& rTip) override + { + m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(nIndex), rTip); + } + + virtual void set_item_tooltip_text(const OString& rIdent, const OUString& rTip) override + { + m_xToolBox->SetQuickHelpText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent)), rTip); + } + + virtual OUString get_item_tooltip_text(const OString& rIdent) const override + { + return m_xToolBox->GetQuickHelpText(m_xToolBox->GetItemId(OUString::fromUtf8(rIdent))); + } + + virtual vcl::ImageType get_icon_size() const override { return m_xToolBox->GetImageSize(); } + + virtual void set_icon_size(vcl::ImageType eType) override + { + ToolBoxButtonSize eButtonSize = ToolBoxButtonSize::DontCare; + switch (eType) + { + case vcl::ImageType::Size16: + eButtonSize = ToolBoxButtonSize::Small; + break; + case vcl::ImageType::Size26: + eButtonSize = ToolBoxButtonSize::Large; + break; + case vcl::ImageType::Size32: + eButtonSize = ToolBoxButtonSize::Size32; + break; + } + if (m_xToolBox->GetToolboxButtonSize() != eButtonSize) + { + m_xToolBox->SetToolboxButtonSize(eButtonSize); + m_xToolBox->queue_resize(); + } + } + + virtual sal_uInt16 get_modifier_state() const override + { + return m_xToolBox->GetModifier(); + } + + int get_drop_index(const Point& rPoint) const override + { + auto nRet = m_xToolBox->GetItemPos(rPoint); + if (nRet == ToolBox::ITEM_NOTFOUND) + return 0; + return nRet; + } + + virtual ~SalInstanceToolbar() override + { + m_xToolBox->SetDropdownClickHdl(Link()); + m_xToolBox->SetSelectHdl(Link()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceToolbar, ClickHdl, ToolBox*, void) +{ + sal_uInt16 nItemId = m_xToolBox->GetCurItemId(); + signal_clicked(m_xToolBox->GetItemCommand(nItemId).toUtf8()); +} + +IMPL_LINK_NOARG(SalInstanceToolbar, DropdownClick, ToolBox*, void) +{ + sal_uInt16 nItemId = m_xToolBox->GetCurItemId(); + set_menu_item_active(m_xToolBox->GetItemCommand(nItemId).toUtf8(), true); +} + +IMPL_LINK(SalInstanceToolbar, MenuToggleListener, VclWindowEvent&, rEvent, void) +{ + if (rEvent.GetId() == VclEventId::WindowEndPopupMode) + { + for (auto& rFloat : m_aFloats) + { + if (rEvent.GetWindow() == rFloat.second) + { + sal_uInt16 nItemId = rFloat.first; + signal_toggle_menu(m_xToolBox->GetItemCommand(nItemId).toUtf8()); + break; + } + } + } +} + +namespace +{ +class SalInstanceSizeGroup : public weld::SizeGroup +{ +private: + std::shared_ptr m_xGroup; + +public: + SalInstanceSizeGroup() + : m_xGroup(std::make_shared()) + { + } + virtual void add_widget(weld::Widget* pWidget) override + { + SalInstanceWidget* pVclWidget = dynamic_cast(pWidget); + assert(pVclWidget && pVclWidget->getWidget()); + pVclWidget->getWidget()->add_to_size_group(m_xGroup); + } + virtual void set_mode(VclSizeGroupMode eMode) override { m_xGroup->set_mode(eMode); } +}; +} + +void SalInstanceContainer::implResetDefault(const vcl::Window* _pWindow) +{ + vcl::Window* pChildLoop = _pWindow->GetWindow(GetWindowType::FirstChild); + while (pChildLoop) + { + // does the window participate in the tabbing order? + if (pChildLoop->GetStyle() & WB_DIALOGCONTROL) + implResetDefault(pChildLoop); + + // is it a button? + WindowType eType = pChildLoop->GetType(); + if ((WindowType::PUSHBUTTON == eType) || (WindowType::OKBUTTON == eType) + || (WindowType::CANCELBUTTON == eType) || (WindowType::HELPBUTTON == eType) + || (WindowType::IMAGEBUTTON == eType) || (WindowType::MENUBUTTON == eType) + || (WindowType::MOREBUTTON == eType)) + { + pChildLoop->SetStyle(pChildLoop->GetStyle() & ~WB_DEFBUTTON); + } + + // the next one ... + pChildLoop = pChildLoop->GetWindow(GetWindowType::Next); + } +} + +SalInstanceContainer::SalInstanceContainer(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceWidget(pContainer, pBuilder, bTakeOwnership) + , m_xContainer(pContainer) +{ +} + +void SalInstanceContainer::move(weld::Widget* pWidget, weld::Container* pNewParent) +{ + SalInstanceWidget* pVclWidget = dynamic_cast(pWidget); + assert(pVclWidget); + SalInstanceContainer* pNewVclParent = dynamic_cast(pNewParent); + assert(!pNewParent || pNewVclParent); + if (pNewVclParent) + pVclWidget->getWidget()->SetParent(pNewVclParent->getWidget()); + else + pVclWidget->getWidget()->SetParentToDefaultWindow(); +} + +void SalInstanceContainer::recursively_unset_default_buttons() +{ + implResetDefault(m_xContainer.get()); +} + +css::uno::Reference SalInstanceContainer::CreateChildFrame() +{ + auto xPage = VclPtr::Create(m_xContainer.get()); + xPage->set_expand(true); + xPage->Show(); + return css::uno::Reference(xPage->GetComponentInterface(), + css::uno::UNO_QUERY); +} + +std::unique_ptr SalInstanceWidget::weld_parent() const +{ + vcl::Window* pParent = m_xWidget->GetParent(); + if (!pParent) + return nullptr; + return std::make_unique(pParent, m_pBuilder, false); +} + +void SalInstanceWidget::draw(VirtualDevice& rOutput) +{ + rOutput.SetOutputSizePixel(m_xWidget->GetSizePixel()); + m_xWidget->PaintToDevice(&rOutput, Point()); +} + +namespace +{ +class SalInstanceBox : public SalInstanceContainer, public virtual weld::Box +{ +public: + SalInstanceBox(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pContainer, pBuilder, bTakeOwnership) + { + } + virtual void reorder_child(weld::Widget* pWidget, int nNewPosition) override + { + SalInstanceWidget* pVclWidget = dynamic_cast(pWidget); + assert(pVclWidget); + pVclWidget->getWidget()->reorderWithinParent(nNewPosition); + } +}; + +void CollectChildren(const vcl::Window& rCurrent, const basegfx::B2IPoint& rTopLeft, + weld::ScreenShotCollection& rControlDataCollection) +{ + if (rCurrent.IsVisible()) + { + const Point aCurrentPos(rCurrent.GetPosPixel()); + const Size aCurrentSize(rCurrent.GetSizePixel()); + const basegfx::B2IPoint aCurrentTopLeft(rTopLeft.getX() + aCurrentPos.X(), + rTopLeft.getY() + aCurrentPos.Y()); + const basegfx::B2IRange aCurrentRange( + aCurrentTopLeft, + aCurrentTopLeft + basegfx::B2IPoint(aCurrentSize.Width(), aCurrentSize.Height())); + + if (!aCurrentRange.isEmpty()) + { + rControlDataCollection.emplace_back(rCurrent.GetHelpId(), aCurrentRange); + } + + for (sal_uInt16 a(0); a < rCurrent.GetChildCount(); a++) + { + vcl::Window* pChild = rCurrent.GetChild(a); + if (nullptr != pChild) + { + CollectChildren(*pChild, aCurrentTopLeft, rControlDataCollection); + } + } + } +} + +} + +void SalInstanceWindow::override_child_help(vcl::Window* pParent) +{ + for (vcl::Window* pChild = pParent->GetWindow(GetWindowType::FirstChild); pChild; + pChild = pChild->GetWindow(GetWindowType::Next)) + override_child_help(pChild); + pParent->SetHelpHdl(LINK(this, SalInstanceWindow, HelpHdl)); +} + +void SalInstanceWindow::clear_child_help(vcl::Window* pParent) +{ + for (vcl::Window* pChild = pParent->GetWindow(GetWindowType::FirstChild); pChild; + pChild = pChild->GetWindow(GetWindowType::Next)) + clear_child_help(pChild); + pParent->SetHelpHdl(Link()); +} + +SalInstanceWindow::SalInstanceWindow(vcl::Window* pWindow, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceContainer(pWindow, pBuilder, bTakeOwnership) + , m_xWindow(pWindow) +{ + override_child_help(m_xWindow); +} + +void SalInstanceWindow::set_title(const OUString& rTitle) { m_xWindow->SetText(rTitle); } + +OUString SalInstanceWindow::get_title() const { return m_xWindow->GetText(); } + +void SalInstanceWindow::set_busy_cursor(bool bBusy) +{ + if (bBusy) + m_xWindow->EnterWait(); + else + m_xWindow->LeaveWait(); +} + +css::uno::Reference SalInstanceWindow::GetXWindow() +{ + css::uno::Reference xWindow(m_xWindow->GetComponentInterface(), + css::uno::UNO_QUERY); + return xWindow; +} + +void SalInstanceWindow::resize_to_request() +{ + if (SystemWindow* pSysWin = dynamic_cast(m_xWindow.get())) + { + pSysWin->setOptimalLayoutSize(); + return; + } + if (DockingWindow* pDockWin = dynamic_cast(m_xWindow.get())) + { + pDockWin->setOptimalLayoutSize(); + return; + } + assert(false && "must be system or docking window"); +} + +void SalInstanceWindow::set_modal(bool bModal) { m_xWindow->ImplGetFrame()->SetModal(bModal); } + +bool SalInstanceWindow::get_modal() const { return m_xWindow->ImplGetFrame()->GetModal(); } + +void SalInstanceWindow::window_move(int x, int y) { m_xWindow->SetPosPixel(Point(x, y)); } + +Size SalInstanceWindow::get_size() const { return m_xWindow->GetSizePixel(); } + +Point SalInstanceWindow::get_position() const { return m_xWindow->GetPosPixel(); } + +tools::Rectangle SalInstanceWindow::get_monitor_workarea() const +{ + return m_xWindow->GetDesktopRectPixel(); +} + +void SalInstanceWindow::set_centered_on_parent(bool /*bTrackGeometryRequests*/) +{ + if (vcl::Window* pParent = m_xWidget->GetParent()) + { + Size aParentGeometry(pParent->GetSizePixel()); + Size aGeometry(m_xWidget->get_preferred_size()); + auto nX = (aParentGeometry.Width() - aGeometry.Width()) / 2; + auto nY = (aParentGeometry.Height() - aGeometry.Height()) / 2; + m_xWidget->SetPosPixel(Point(nX, nY)); + } +} + +bool SalInstanceWindow::get_resizable() const { return m_xWindow->GetStyle() & WB_SIZEABLE; } + +bool SalInstanceWindow::has_toplevel_focus() const { return m_xWindow->HasChildPathFocus(); } + +void SalInstanceWindow::present() +{ + m_xWindow->ToTop(ToTopFlags::RestoreWhenMin | ToTopFlags::ForegroundTask); +} + +void SalInstanceWindow::set_window_state(const OString& rStr) +{ + SystemWindow* pSysWin = dynamic_cast(m_xWindow.get()); + assert(pSysWin); + pSysWin->SetWindowState(rStr); +} + +OString SalInstanceWindow::get_window_state(WindowStateMask nMask) const +{ + SystemWindow* pSysWin = dynamic_cast(m_xWindow.get()); + assert(pSysWin); + return pSysWin->GetWindowState(nMask); +} + +SystemEnvData SalInstanceWindow::get_system_data() const { return *m_xWindow->GetSystemData(); } + +void SalInstanceWindow::connect_toplevel_focus_changed(const Link& rLink) +{ + ensure_event_listener(); + weld::Window::connect_toplevel_focus_changed(rLink); +} + +void SalInstanceWindow::HandleEventListener(VclWindowEvent& rEvent) +{ + if (rEvent.GetId() == VclEventId::WindowActivate + || rEvent.GetId() == VclEventId::WindowDeactivate) + { + signal_toplevel_focus_changed(); + return; + } + SalInstanceContainer::HandleEventListener(rEvent); +} + +void SalInstanceWindow::draw(VirtualDevice& rOutput) +{ + SystemWindow* pSysWin = dynamic_cast(m_xWindow.get()); + assert(pSysWin); + pSysWin->createScreenshot(rOutput); +} + +weld::ScreenShotCollection SalInstanceWindow::collect_screenshot_data() +{ + weld::ScreenShotCollection aRet; + + // collect all children. Choose start pos to be negative + // of target dialog's position to get all positions relative to (0,0) + const Point aParentPos(m_xWindow->GetPosPixel()); + const basegfx::B2IPoint aTopLeft(-aParentPos.X(), -aParentPos.Y()); + CollectChildren(*m_xWindow, aTopLeft, aRet); + + return aRet; +} + +SalInstanceWindow::~SalInstanceWindow() { clear_child_help(m_xWindow); } + +IMPL_LINK_NOARG(SalInstanceWindow, HelpHdl, vcl::Window&, bool) +{ + help(); + return false; +} + +typedef std::set> winset; + +namespace +{ +void hideUnless(const vcl::Window* pTop, const winset& rVisibleWidgets, + std::vector>& rWasVisibleWidgets) +{ + for (vcl::Window* pChild = pTop->GetWindow(GetWindowType::FirstChild); pChild; + pChild = pChild->GetWindow(GetWindowType::Next)) + { + if (!pChild->IsVisible()) + continue; + if (rVisibleWidgets.find(pChild) == rVisibleWidgets.end()) + { + rWasVisibleWidgets.emplace_back(pChild); + pChild->Hide(); + } + else if (isContainerWindow(pChild)) + { + hideUnless(pChild, rVisibleWidgets, rWasVisibleWidgets); + } + } +} +} + +SalInstanceDialog::SalInstanceDialog(::Dialog* pDialog, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceWindow(pDialog, pBuilder, bTakeOwnership) + , m_xDialog(pDialog) + , m_nOldEditWidthReq(0) + , m_nOldBorderWidth(0) +{ + const bool bScreenshotMode(officecfg::Office::Common::Misc::ScreenshotMode::get()); + if (bScreenshotMode) + { + m_xDialog->SetPopupMenuHdl(LINK(this, SalInstanceDialog, PopupScreenShotMenuHdl)); + } +} + +bool SalInstanceDialog::runAsync(std::shared_ptr aOwner, + const std::function& rEndDialogFn) +{ + VclAbstractDialog::AsyncContext aCtx; + aCtx.mxOwnerDialogController = aOwner; + aCtx.maEndDialogFn = rEndDialogFn; + VclButtonBox* pActionArea = m_xDialog->get_action_area(); + if (pActionArea) + pActionArea->sort_native_button_order(); + return m_xDialog->StartExecuteAsync(aCtx); +} + +bool SalInstanceDialog::runAsync(std::shared_ptr const& rxSelf, + const std::function& rEndDialogFn) +{ + assert(rxSelf.get() == this); + VclAbstractDialog::AsyncContext aCtx; + // In order to store a shared_ptr to ourself, we have to have been constructed by make_shared, + // which is that rxSelf enforces. + aCtx.mxOwnerSelf = rxSelf; + aCtx.maEndDialogFn = rEndDialogFn; + VclButtonBox* pActionArea = m_xDialog->get_action_area(); + if (pActionArea) + pActionArea->sort_native_button_order(); + return m_xDialog->StartExecuteAsync(aCtx); +} + +void SalInstanceDialog::collapse(weld::Widget* pEdit, weld::Widget* pButton) +{ + SalInstanceWidget* pVclEdit = dynamic_cast(pEdit); + assert(pVclEdit); + SalInstanceWidget* pVclButton = dynamic_cast(pButton); + + vcl::Window* pRefEdit = pVclEdit->getWidget(); + vcl::Window* pRefBtn = pVclButton ? pVclButton->getWidget() : nullptr; + + auto nOldEditWidth = pRefEdit->GetSizePixel().Width(); + m_nOldEditWidthReq = pRefEdit->get_width_request(); + + //We want just pRefBtn and pRefEdit to be shown + //mark widgets we want to be visible, starting with pRefEdit + //and all its direct parents. + winset aVisibleWidgets; + vcl::Window* pContentArea = m_xDialog->get_content_area(); + for (vcl::Window* pCandidate = pRefEdit; + pCandidate && (pCandidate != pContentArea && pCandidate->IsVisible()); + pCandidate = pCandidate->GetWindow(GetWindowType::RealParent)) + { + aVisibleWidgets.insert(pCandidate); + } + //same again with pRefBtn, except stop if there's a + //shared parent in the existing widgets + for (vcl::Window* pCandidate = pRefBtn; + pCandidate && (pCandidate != pContentArea && pCandidate->IsVisible()); + pCandidate = pCandidate->GetWindow(GetWindowType::RealParent)) + { + if (aVisibleWidgets.insert(pCandidate).second) + break; + } + + //hide everything except the aVisibleWidgets + hideUnless(pContentArea, aVisibleWidgets, m_aHiddenWidgets); + + // the insert function case has an initially hidden edit widget, so it has + // not start size, so take larger of actual size and size request + pRefEdit->set_width_request(std::max(nOldEditWidth, m_nOldEditWidthReq)); + m_nOldBorderWidth = m_xDialog->get_border_width(); + m_xDialog->set_border_width(0); + if (vcl::Window* pActionArea = m_xDialog->get_action_area()) + pActionArea->Hide(); + m_xDialog->setOptimalLayoutSize(); + m_xRefEdit = pRefEdit; +} + +void SalInstanceDialog::undo_collapse() +{ + // All others: Show(); + for (VclPtr const& pWindow : m_aHiddenWidgets) + { + pWindow->Show(); + } + m_aHiddenWidgets.clear(); + + m_xRefEdit->set_width_request(m_nOldEditWidthReq); + m_xRefEdit.clear(); + m_xDialog->set_border_width(m_nOldBorderWidth); + if (vcl::Window* pActionArea = m_xDialog->get_action_area()) + pActionArea->Show(); + m_xDialog->setOptimalLayoutSize(); +} + +void SalInstanceDialog::SetInstallLOKNotifierHdl( + const Link& rLink) +{ + m_xDialog->SetInstallLOKNotifierHdl(rLink); +} + +int SalInstanceDialog::run() +{ + VclButtonBox* pActionArea = m_xDialog->get_action_area(); + if (pActionArea) + pActionArea->sort_native_button_order(); + return m_xDialog->Execute(); +} + +void SalInstanceDialog::response(int nResponse) { m_xDialog->EndDialog(nResponse); } + +void SalInstanceDialog::add_button(const OUString& rText, int nResponse, const OString& rHelpId) +{ + VclButtonBox* pBox = m_xDialog->get_action_area(); + VclPtr xButton( + VclPtr::Create(pBox, WB_CLIPCHILDREN | WB_CENTER | WB_VCENTER)); + xButton->SetText(rText); + xButton->SetHelpId(rHelpId); + + switch (nResponse) + { + case RET_OK: + xButton->set_id("ok"); + break; + case RET_CLOSE: + xButton->set_id("close"); + break; + case RET_CANCEL: + xButton->set_id("cancel"); + break; + case RET_YES: + xButton->set_id("yes"); + break; + case RET_NO: + xButton->set_id("no"); + break; + } + + xButton->Show(); + m_xDialog->add_button(xButton, nResponse, true); +} + +void SalInstanceDialog::set_modal(bool bModal) +{ + if (get_modal() == bModal) + return; + m_xDialog->SetModalInputMode(bModal); +} + +bool SalInstanceDialog::get_modal() const { return m_xDialog->IsModalInputMode(); } + +void SalInstanceDialog::set_default_response(int nResponse) +{ + m_xDialog->set_default_response(nResponse); +} + +weld::Container* SalInstanceDialog::weld_content_area() +{ + return new SalInstanceContainer(m_xDialog->get_content_area(), m_pBuilder, false); +} + +IMPL_LINK(SalInstanceDialog, PopupScreenShotMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (CommandEventId::ContextMenu == rCEvt.GetCommand()) + { + const Point aMenuPos(rCEvt.GetMousePosPixel()); + ScopedVclPtrInstance aMenu; + sal_uInt16 nLocalID(1); + + aMenu->InsertItem(nLocalID, VclResId(SV_BUTTONTEXT_SCREENSHOT)); + aMenu->SetHelpText(nLocalID, VclResId(SV_HELPTEXT_SCREENSHOT)); + aMenu->SetHelpId(nLocalID, "InteractiveScreenshotMode"); + aMenu->EnableItem(nLocalID); + + const sal_uInt16 nId(aMenu->Execute(m_xDialog, aMenuPos)); + + // 0 == no selection (so not usable as ID) + if (0 != nId) + { + // open screenshot annotation dialog + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + VclPtr pTmp + = pFact->CreateScreenshotAnnotationDlg(*this); + ScopedVclPtr pDialog(pTmp); + + if (pDialog) + { + // currently just execute the dialog, no need to do + // different things for ok/cancel. This may change later, + // for that case use 'if (pDlg->Execute() == RET_OK)' + pDialog->Execute(); + } + } + + // consume event when: + // - CommandEventId::ContextMenu + // - bScreenshotMode + return true; + } + + return false; +} + +SalInstanceMessageDialog::SalInstanceMessageDialog(::MessageDialog* pDialog, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership) + , m_xMessageDialog(pDialog) +{ +} + +void SalInstanceMessageDialog::set_primary_text(const OUString& rText) +{ + m_xMessageDialog->set_primary_text(rText); +} + +OUString SalInstanceMessageDialog::get_primary_text() const +{ + return m_xMessageDialog->get_primary_text(); +} + +void SalInstanceMessageDialog::set_secondary_text(const OUString& rText) +{ + m_xMessageDialog->set_secondary_text(rText); +} + +OUString SalInstanceMessageDialog::get_secondary_text() const +{ + return m_xMessageDialog->get_secondary_text(); +} + +weld::Container* SalInstanceMessageDialog::weld_message_area() +{ + return new SalInstanceContainer(m_xMessageDialog->get_message_area(), m_pBuilder, false); +} + +namespace +{ + +class SalInstanceAssistant : public SalInstanceDialog, public virtual weld::Assistant +{ +private: + VclPtr m_xWizard; + std::vector> m_aPages; + std::vector> m_aAddedPages; + std::vector m_aIds; + std::vector> m_aAddedGrids; + Idle m_aUpdateRoadmapIdle; + + int find_page(const OString& rIdent) const + { + for (size_t i = 0; i < m_aAddedPages.size(); ++i) + { + if (m_aAddedPages[i]->get_id().toUtf8() == rIdent) + return i; + } + return -1; + } + + int find_id(int nId) const + { + for (size_t i = 0; i < m_aIds.size(); ++i) + { + if (nId == m_aIds[i]) + return i; + } + return -1; + } + + DECL_LINK(OnRoadmapItemSelected, LinkParamNone*, void); + DECL_LINK(UpdateRoadmap_Hdl, Timer*, void); + +public: + SalInstanceAssistant(vcl::RoadmapWizard* pDialog, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceDialog(pDialog, pBuilder, bTakeOwnership) + , m_xWizard(pDialog) + { + m_xWizard->SetItemSelectHdl(LINK(this, SalInstanceAssistant, OnRoadmapItemSelected)); + + m_aUpdateRoadmapIdle.SetInvokeHandler(LINK(this, SalInstanceAssistant, UpdateRoadmap_Hdl)); + m_aUpdateRoadmapIdle.SetPriority(TaskPriority::HIGHEST); + } + + virtual int get_current_page() const override { return find_id(m_xWizard->GetCurLevel()); } + + virtual int get_n_pages() const override { return m_aAddedPages.size(); } + + virtual OString get_page_ident(int nPage) const override + { + return m_aAddedPages[nPage]->get_id().toUtf8(); + } + + virtual OString get_current_page_ident() const override + { + return get_page_ident(get_current_page()); + } + + virtual void set_current_page(int nPage) override + { + disable_notify_events(); + + // take the first shown page as the size for all pages + if (m_xWizard->GetPageSizePixel().Width() == 0) + { + Size aFinalSize; + for (int i = 0, nPages = get_n_pages(); i < nPages; ++i) + { + TabPage* pPage = m_xWizard->GetPage(m_aIds[i]); + assert(pPage); + Size aPageSize(pPage->get_preferred_size()); + if (aPageSize.Width() > aFinalSize.Width()) + aFinalSize.setWidth(aPageSize.Width()); + if (aPageSize.Height() > aFinalSize.Height()) + aFinalSize.setHeight(aPageSize.Height()); + } + m_xWizard->SetPageSizePixel(aFinalSize); + } + + (void)m_xWizard->ShowPage(m_aIds[nPage]); + enable_notify_events(); + } + + virtual void set_current_page(const OString& rIdent) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + set_current_page(nIndex); + } + + virtual void set_page_index(const OString& rIdent, int nNewIndex) override + { + int nOldIndex = find_page(rIdent); + + if (nOldIndex == -1) + return; + + if (nOldIndex == nNewIndex) + return; + + disable_notify_events(); + + auto entry = std::move(m_aAddedPages[nOldIndex]); + m_aAddedPages.erase(m_aAddedPages.begin() + nOldIndex); + m_aAddedPages.insert(m_aAddedPages.begin() + nNewIndex, std::move(entry)); + + int nId = m_aIds[nOldIndex]; + m_aIds.erase(m_aIds.begin() + nOldIndex); + m_aIds.insert(m_aIds.begin() + nNewIndex, nId); + + m_aUpdateRoadmapIdle.Start(); + + enable_notify_events(); + } + + virtual weld::Container* append_page(const OString& rIdent) override + { + VclPtrInstance xPage(m_xWizard); + VclPtrInstance xGrid(xPage); + xPage->set_id(OUString::fromUtf8(rIdent)); + xPage->Show(); + xGrid->set_hexpand(true); + xGrid->set_vexpand(true); + xGrid->Show(); + m_xWizard->AddPage(xPage); + m_aIds.push_back(m_aAddedPages.size()); + m_xWizard->SetPage(m_aIds.back(), xPage); + m_aAddedPages.push_back(xPage); + m_aAddedGrids.push_back(xGrid); + + m_aUpdateRoadmapIdle.Start(); + + m_aPages.emplace_back(new SalInstanceContainer(xGrid, m_pBuilder, false)); + return m_aPages.back().get(); + } + + virtual OUString get_page_title(const OString& rIdent) const override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return OUString(); + return m_aAddedPages[nIndex]->GetText(); + } + + virtual void set_page_title(const OString& rIdent, const OUString& rTitle) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + if (m_aAddedPages[nIndex]->GetText() != rTitle) + { + disable_notify_events(); + m_aAddedPages[nIndex]->SetText(rTitle); + m_aUpdateRoadmapIdle.Start(); + enable_notify_events(); + } + } + + virtual void set_page_sensitive(const OString& rIdent, bool bSensitive) override + { + int nIndex = find_page(rIdent); + if (nIndex == -1) + return; + if (m_aAddedPages[nIndex]->IsEnabled() != bSensitive) + { + disable_notify_events(); + m_aAddedPages[nIndex]->Enable(bSensitive); + m_aUpdateRoadmapIdle.Start(); + enable_notify_events(); + } + } + + virtual void set_page_side_help_id(const OString& rHelpId) override + { + m_xWizard->SetRoadmapHelpId(rHelpId); + } + + weld::Button* weld_widget_for_response(int nResponse) override; + + virtual ~SalInstanceAssistant() override + { + for (auto& rGrid : m_aAddedGrids) + rGrid.disposeAndClear(); + for (auto& rPage : m_aAddedPages) + rPage.disposeAndClear(); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceAssistant, OnRoadmapItemSelected, LinkParamNone*, void) +{ + if (notify_events_disabled()) + return; + auto nCurItemId = m_xWizard->GetCurrentRoadmapItemID(); + int nPageIndex(find_id(nCurItemId)); + if (!signal_jump_page(get_page_ident(nPageIndex)) && nCurItemId != m_xWizard->GetCurLevel()) + m_xWizard->SelectRoadmapItemByID(m_xWizard->GetCurLevel()); +} + +IMPL_LINK_NOARG(SalInstanceAssistant, UpdateRoadmap_Hdl, Timer*, void) +{ + disable_notify_events(); + + m_xWizard->DeleteRoadmapItems(); + + int nPos = 0; + for (size_t i = 0; i < m_aAddedPages.size(); ++i) + { + const OUString& rLabel = m_aAddedPages[i]->GetText(); + bool bSensitive = m_aAddedPages[i]->IsEnabled(); + if (rLabel.isEmpty()) + continue; + m_xWizard->InsertRoadmapItem(nPos++, rLabel, m_aIds[i], bSensitive); + } + + m_xWizard->SelectRoadmapItemByID(m_aIds[get_current_page()]); + + m_xWizard->ShowRoadmap(nPos != 0); + + enable_notify_events(); +} + +namespace +{ +class SalInstanceFrame : public SalInstanceContainer, public virtual weld::Frame +{ +private: + VclPtr m_xFrame; + +public: + SalInstanceFrame(VclFrame* pFrame, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pFrame, pBuilder, bTakeOwnership) + , m_xFrame(pFrame) + { + } + + virtual void set_label(const OUString& rText) override { m_xFrame->set_label(rText); } + + virtual OUString get_label() const override { return m_xFrame->get_label(); } + + virtual std::unique_ptr weld_label_widget() const override; +}; + +class SalInstancePaned : public SalInstanceContainer, public virtual weld::Paned +{ +private: + VclPtr m_xPaned; + +public: + SalInstancePaned(VclPaned* pPaned, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pPaned, pBuilder, bTakeOwnership) + , m_xPaned(pPaned) + { + } + + virtual void set_position(int nPos) override + { + m_xPaned->set_position(nPos); + } + + virtual int get_position() const override + { + return m_xPaned->get_position(); + } +}; + +class SalInstanceScrolledWindow : public SalInstanceContainer, public virtual weld::ScrolledWindow +{ +private: + VclPtr m_xScrolledWindow; + Link m_aOrigVScrollHdl; + Link m_aOrigHScrollHdl; + bool m_bUserManagedScrolling; + + DECL_LINK(VscrollHdl, ScrollBar*, void); + DECL_LINK(HscrollHdl, ScrollBar*, void); + +public: + SalInstanceScrolledWindow(VclScrolledWindow* pScrolledWindow, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceContainer(pScrolledWindow, pBuilder, bTakeOwnership) + , m_xScrolledWindow(pScrolledWindow) + , m_bUserManagedScrolling(false) + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + m_aOrigVScrollHdl = rVertScrollBar.GetScrollHdl(); + rVertScrollBar.SetScrollHdl(LINK(this, SalInstanceScrolledWindow, VscrollHdl)); + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + m_aOrigHScrollHdl = rHorzScrollBar.GetScrollHdl(); + rHorzScrollBar.SetScrollHdl(LINK(this, SalInstanceScrolledWindow, HscrollHdl)); + } + + virtual void hadjustment_configure(int value, int lower, int upper, int step_increment, + int page_increment, int page_size) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + rHorzScrollBar.SetRangeMin(lower); + rHorzScrollBar.SetRangeMax(upper); + rHorzScrollBar.SetLineSize(step_increment); + rHorzScrollBar.SetPageSize(page_increment); + rHorzScrollBar.SetThumbPos(value); + rHorzScrollBar.SetVisibleSize(page_size); + } + + virtual int hadjustment_get_value() const override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.GetThumbPos(); + } + + virtual void hadjustment_set_value(int value) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + rHorzScrollBar.SetThumbPos(value); + if (!m_bUserManagedScrolling) + m_aOrigHScrollHdl.Call(&rHorzScrollBar); + } + + virtual int hadjustment_get_upper() const override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.GetRangeMax(); + } + + virtual void hadjustment_set_upper(int upper) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + rHorzScrollBar.SetRangeMax(upper); + } + + virtual int hadjustment_get_page_size() const override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.GetVisibleSize(); + } + + virtual void hadjustment_set_page_size(int size) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.SetVisibleSize(size); + } + + virtual void hadjustment_set_page_increment(int size) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.SetPageSize(size); + } + + virtual void hadjustment_set_step_increment(int size) override + { + ScrollBar& rHorzScrollBar = m_xScrolledWindow->getHorzScrollBar(); + return rHorzScrollBar.SetLineSize(size); + } + + virtual void set_hpolicy(VclPolicyType eHPolicy) override + { + WinBits nWinBits = m_xScrolledWindow->GetStyle() & ~(WB_AUTOHSCROLL | WB_HSCROLL); + if (eHPolicy == VclPolicyType::ALWAYS) + nWinBits |= WB_HSCROLL; + else if (eHPolicy == VclPolicyType::AUTOMATIC) + nWinBits |= WB_AUTOHSCROLL; + m_xScrolledWindow->SetStyle(nWinBits); + m_xScrolledWindow->queue_resize(); + } + + virtual VclPolicyType get_hpolicy() const override + { + WinBits nWinBits = m_xScrolledWindow->GetStyle(); + if (nWinBits & WB_AUTOHSCROLL) + return VclPolicyType::AUTOMATIC; + else if (nWinBits & WB_HSCROLL) + return VclPolicyType::ALWAYS; + return VclPolicyType::NEVER; + } + + virtual int get_hscroll_height() const override + { + return m_xScrolledWindow->getHorzScrollBar().get_preferred_size().Height(); + } + + virtual void vadjustment_configure(int value, int lower, int upper, int step_increment, + int page_increment, int page_size) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + rVertScrollBar.SetRangeMin(lower); + rVertScrollBar.SetRangeMax(upper); + rVertScrollBar.SetLineSize(step_increment); + rVertScrollBar.SetPageSize(page_increment); + rVertScrollBar.SetThumbPos(value); + rVertScrollBar.SetVisibleSize(page_size); + } + + virtual int vadjustment_get_value() const override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.GetThumbPos(); + } + + virtual void vadjustment_set_value(int value) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + rVertScrollBar.SetThumbPos(value); + if (!m_bUserManagedScrolling) + m_aOrigVScrollHdl.Call(&rVertScrollBar); + } + + virtual int vadjustment_get_upper() const override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.GetRangeMax(); + } + + virtual void vadjustment_set_upper(int upper) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + rVertScrollBar.SetRangeMax(upper); + } + + virtual int vadjustment_get_lower() const override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.GetRangeMin(); + } + + virtual void vadjustment_set_lower(int lower) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + rVertScrollBar.SetRangeMin(lower); + } + + virtual int vadjustment_get_page_size() const override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.GetVisibleSize(); + } + + virtual void vadjustment_set_page_size(int size) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.SetVisibleSize(size); + } + + virtual void vadjustment_set_page_increment(int size) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.SetPageSize(size); + } + + virtual void vadjustment_set_step_increment(int size) override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + return rVertScrollBar.SetLineSize(size); + } + + virtual void set_vpolicy(VclPolicyType eVPolicy) override + { + WinBits nWinBits = m_xScrolledWindow->GetStyle() & ~(WB_AUTOVSCROLL | WB_VSCROLL); + if (eVPolicy == VclPolicyType::ALWAYS) + nWinBits |= WB_VSCROLL; + else if (eVPolicy == VclPolicyType::AUTOMATIC) + nWinBits |= WB_AUTOVSCROLL; + m_xScrolledWindow->SetStyle(nWinBits); + m_xScrolledWindow->queue_resize(); + } + + virtual VclPolicyType get_vpolicy() const override + { + WinBits nWinBits = m_xScrolledWindow->GetStyle(); + if (nWinBits & WB_AUTOVSCROLL) + return VclPolicyType::AUTOMATIC; + else if (nWinBits & WB_VSCROLL) + return VclPolicyType::ALWAYS; + return VclPolicyType::NEVER; + } + + virtual int get_vscroll_width() const override + { + return m_xScrolledWindow->getVertScrollBar().get_preferred_size().Width(); + } + + virtual void set_user_managed_scrolling() override + { + m_bUserManagedScrolling = true; + m_xScrolledWindow->setUserManagedScrolling(true); + } + + virtual ~SalInstanceScrolledWindow() override + { + ScrollBar& rVertScrollBar = m_xScrolledWindow->getVertScrollBar(); + rVertScrollBar.SetScrollHdl(m_aOrigVScrollHdl); + } +}; + +} + +IMPL_LINK(SalInstanceScrolledWindow, VscrollHdl, ScrollBar*, pScrollBar, void) +{ + signal_vadjustment_changed(); + if (!m_bUserManagedScrolling) + m_aOrigVScrollHdl.Call(pScrollBar); +} + +IMPL_LINK_NOARG(SalInstanceScrolledWindow, HscrollHdl, ScrollBar*, void) +{ + signal_hadjustment_changed(); + if (!m_bUserManagedScrolling) + m_aOrigHScrollHdl.Call(&m_xScrolledWindow->getHorzScrollBar()); +} + +SalInstanceNotebook::SalInstanceNotebook(TabControl* pNotebook, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pNotebook, pBuilder, bTakeOwnership) + , m_xNotebook(pNotebook) +{ + m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceNotebook, ActivatePageHdl)); + m_xNotebook->SetDeactivatePageHdl(LINK(this, SalInstanceNotebook, DeactivatePageHdl)); +} + +int SalInstanceNotebook::get_current_page() const +{ + return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId()); +} + +OString SalInstanceNotebook::get_page_ident(int nPage) const +{ + return m_xNotebook->GetPageName(m_xNotebook->GetPageId(nPage)); +} + +OString SalInstanceNotebook::get_current_page_ident() const +{ + return m_xNotebook->GetPageName(m_xNotebook->GetCurPageId()); +} + +weld::Container* SalInstanceNotebook::get_page(const OString& rIdent) const +{ + sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent); + sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId); + if (nPageIndex == TAB_PAGE_NOTFOUND) + return nullptr; + TabPage* pPage = m_xNotebook->GetTabPage(nPageId); + vcl::Window* pChild = pPage->GetChild(0); + if (m_aPages.size() < nPageIndex + 1U) + m_aPages.resize(nPageIndex + 1U); + if (!m_aPages[nPageIndex]) + m_aPages[nPageIndex] = std::make_shared(pChild, m_pBuilder, false); + return m_aPages[nPageIndex].get(); +} + +void SalInstanceNotebook::set_current_page(int nPage) +{ + m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage)); +} + +void SalInstanceNotebook::set_current_page(const OString& rIdent) +{ + m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(rIdent)); +} + +void SalInstanceNotebook::remove_page(const OString& rIdent) +{ + sal_uInt16 nPageId = m_xNotebook->GetPageId(rIdent); + sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(nPageId); + if (nPageIndex == TAB_PAGE_NOTFOUND) + return; + + m_xNotebook->RemovePage(nPageId); + if (nPageIndex < m_aPages.size()) + m_aPages.erase(m_aPages.begin() + nPageIndex); + + auto iter = m_aAddedPages.find(rIdent); + if (iter != m_aAddedPages.end()) + { + iter->second.second.disposeAndClear(); + iter->second.first.disposeAndClear(); + m_aAddedPages.erase(iter); + } +} + +void SalInstanceNotebook::insert_page(const OString& rIdent, const OUString& rLabel, int nPos) +{ + sal_uInt16 nPageCount = m_xNotebook->GetPageCount(); + sal_uInt16 nLastPageId = nPageCount ? m_xNotebook->GetPageId(nPageCount - 1) : 0; + sal_uInt16 nNewPageId = nLastPageId + 1; + m_xNotebook->InsertPage(nNewPageId, rLabel, nPos == -1 ? TAB_APPEND : nPos); + VclPtrInstance xPage(m_xNotebook); + VclPtrInstance xGrid(xPage); + xPage->Show(); + xGrid->set_hexpand(true); + xGrid->set_vexpand(true); + xGrid->Show(); + m_xNotebook->SetTabPage(nNewPageId, xPage); + m_xNotebook->SetPageName(nNewPageId, rIdent); + m_aAddedPages.try_emplace(rIdent, xPage, xGrid); +} + +int SalInstanceNotebook::get_n_pages() const { return m_xNotebook->GetPageCount(); } + +OUString SalInstanceNotebook::get_tab_label_text(const OString& rIdent) const +{ + return m_xNotebook->GetPageText(m_xNotebook->GetPageId(rIdent)); +} + +void SalInstanceNotebook::set_tab_label_text(const OString& rIdent, const OUString& rText) +{ + return m_xNotebook->SetPageText(m_xNotebook->GetPageId(rIdent), rText); +} + +SalInstanceNotebook::~SalInstanceNotebook() +{ + for (auto& rItem : m_aAddedPages) + { + rItem.second.second.disposeAndClear(); + rItem.second.first.disposeAndClear(); + } + m_xNotebook->SetActivatePageHdl(Link()); + m_xNotebook->SetDeactivatePageHdl(Link()); +} + +IMPL_LINK_NOARG(SalInstanceNotebook, DeactivatePageHdl, TabControl*, bool) +{ + return !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident()); +} + +IMPL_LINK_NOARG(SalInstanceNotebook, ActivatePageHdl, TabControl*, void) +{ + m_aEnterPageHdl.Call(get_current_page_ident()); +} + +namespace +{ +class SalInstanceVerticalNotebook : public SalInstanceContainer, public virtual weld::Notebook +{ +private: + VclPtr m_xNotebook; + mutable std::vector> m_aPages; + + DECL_LINK(DeactivatePageHdl, VerticalTabControl*, bool); + DECL_LINK(ActivatePageHdl, VerticalTabControl*, void); + +public: + SalInstanceVerticalNotebook(VerticalTabControl* pNotebook, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceContainer(pNotebook, pBuilder, bTakeOwnership) + , m_xNotebook(pNotebook) + { + m_xNotebook->SetActivatePageHdl(LINK(this, SalInstanceVerticalNotebook, ActivatePageHdl)); + m_xNotebook->SetDeactivatePageHdl( + LINK(this, SalInstanceVerticalNotebook, DeactivatePageHdl)); + } + + virtual int get_current_page() const override + { + return m_xNotebook->GetPagePos(m_xNotebook->GetCurPageId()); + } + + virtual OString get_page_ident(int nPage) const override + { + return m_xNotebook->GetPageId(nPage); + } + + virtual OString get_current_page_ident() const override { return m_xNotebook->GetCurPageId(); } + + virtual weld::Container* get_page(const OString& rIdent) const override + { + sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(rIdent); + if (nPageIndex == TAB_PAGE_NOTFOUND) + return nullptr; + auto pChild = m_xNotebook->GetPage(rIdent); + if (m_aPages.size() < nPageIndex + 1U) + m_aPages.resize(nPageIndex + 1U); + if (!m_aPages[nPageIndex]) + m_aPages[nPageIndex].reset(new SalInstanceContainer(pChild, m_pBuilder, false)); + return m_aPages[nPageIndex].get(); + } + + virtual void set_current_page(int nPage) override + { + m_xNotebook->SetCurPageId(m_xNotebook->GetPageId(nPage)); + } + + virtual void set_current_page(const OString& rIdent) override + { + m_xNotebook->SetCurPageId(rIdent); + } + + virtual void remove_page(const OString& rIdent) override + { + sal_uInt16 nPageIndex = m_xNotebook->GetPagePos(rIdent); + if (nPageIndex == TAB_PAGE_NOTFOUND) + return; + m_xNotebook->RemovePage(rIdent); + if (nPageIndex < m_aPages.size()) + m_aPages.erase(m_aPages.begin() + nPageIndex); + } + + virtual void insert_page(const OString& rIdent, const OUString& rLabel, int nPos) override + { + VclPtrInstance xGrid(m_xNotebook->GetPageParent()); + xGrid->set_hexpand(true); + xGrid->set_vexpand(true); + m_xNotebook->InsertPage(rIdent, rLabel, Image(), "", xGrid, nPos); + } + + virtual int get_n_pages() const override { return m_xNotebook->GetPageCount(); } + + virtual void set_tab_label_text(const OString& rIdent, const OUString& rText) override + { + return m_xNotebook->SetPageText(rIdent, rText); + } + + virtual OUString get_tab_label_text(const OString& rIdent) const override + { + return m_xNotebook->GetPageText(rIdent); + } + + virtual ~SalInstanceVerticalNotebook() override + { + m_xNotebook->SetActivatePageHdl(Link()); + m_xNotebook->SetDeactivatePageHdl(Link()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceVerticalNotebook, DeactivatePageHdl, VerticalTabControl*, bool) +{ + return !m_aLeavePageHdl.IsSet() || m_aLeavePageHdl.Call(get_current_page_ident()); +} + +IMPL_LINK_NOARG(SalInstanceVerticalNotebook, ActivatePageHdl, VerticalTabControl*, void) +{ + m_aEnterPageHdl.Call(get_current_page_ident()); +} + +SalInstanceButton::SalInstanceButton(::Button* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pButton, pBuilder, bTakeOwnership) + , m_xButton(pButton) + , m_aOldClickHdl(pButton->GetClickHdl()) +{ + m_xButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl)); +} + +void SalInstanceButton::set_label(const OUString& rText) { m_xButton->SetText(rText); } + +void SalInstanceButton::set_image(VirtualDevice* pDevice) +{ + m_xButton->SetImageAlign(ImageAlign::Left); + if (pDevice) + m_xButton->SetModeImage(createImage(*pDevice)); + else + m_xButton->SetModeImage(Image()); +} + +void SalInstanceButton::set_image(const css::uno::Reference& rImage) +{ + m_xButton->SetImageAlign(ImageAlign::Left); + m_xButton->SetModeImage(Image(rImage)); +} + +void SalInstanceButton::set_from_icon_name(const OUString& rIconName) +{ + m_xButton->SetModeImage(Image(StockImage::Yes, rIconName)); +} + +void SalInstanceButton::set_label_line_wrap(bool wrap) +{ + WinBits nBits = m_xButton->GetStyle(); + nBits &= ~WB_WORDBREAK; + if (wrap) + nBits |= WB_WORDBREAK; + m_xButton->SetStyle(nBits); + m_xButton->queue_resize(); +} + +OUString SalInstanceButton::get_label() const { return m_xButton->GetText(); } + +SalInstanceButton::~SalInstanceButton() { m_xButton->SetClickHdl(Link<::Button*, void>()); } + +IMPL_LINK(SalInstanceButton, ClickHdl, ::Button*, pButton, void) +{ + //if there's no handler set, disengage our intercept and + //run the click again to get default behaviour for cancel/ok + //etc buttons. + if (!m_aClickHdl.IsSet()) + { + pButton->SetClickHdl(m_aOldClickHdl); + pButton->Click(); + pButton->SetClickHdl(LINK(this, SalInstanceButton, ClickHdl)); + return; + } + signal_clicked(); +} + +weld::Button* SalInstanceDialog::weld_widget_for_response(int nResponse) +{ + PushButton* pButton = dynamic_cast(m_xDialog->get_widget_for_response(nResponse)); + return pButton ? new SalInstanceButton(pButton, nullptr, false) : nullptr; +} + +weld::Button* SalInstanceAssistant::weld_widget_for_response(int nResponse) +{ + PushButton* pButton = nullptr; + if (nResponse == RET_YES) + pButton = m_xWizard->m_pNextPage; + else if (nResponse == RET_NO) + pButton = m_xWizard->m_pPrevPage; + else if (nResponse == RET_OK) + pButton = m_xWizard->m_pFinish; + else if (nResponse == RET_CANCEL) + pButton = m_xWizard->m_pCancel; + else if (nResponse == RET_HELP) + pButton = m_xWizard->m_pHelp; + if (pButton) + return new SalInstanceButton(pButton, nullptr, false); + return nullptr; +} + +namespace +{ +class SalInstanceMenuButton : public SalInstanceButton, public virtual weld::MenuButton +{ +private: + VclPtr<::MenuButton> m_xMenuButton; + sal_uInt16 m_nLastId; + + DECL_LINK(MenuSelectHdl, ::MenuButton*, void); + DECL_LINK(ActivateHdl, ::MenuButton*, void); + +public: + SalInstanceMenuButton(::MenuButton* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceButton(pButton, pBuilder, bTakeOwnership) + , m_xMenuButton(pButton) + , m_nLastId(0) + { + m_xMenuButton->SetActivateHdl(LINK(this, SalInstanceMenuButton, ActivateHdl)); + m_xMenuButton->SetSelectHdl(LINK(this, SalInstanceMenuButton, MenuSelectHdl)); + if (PopupMenu* pMenu = m_xMenuButton->GetPopupMenu()) + { + pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); + const auto nCount = pMenu->GetItemCount(); + m_nLastId = nCount ? pMenu->GetItemId(nCount - 1) : 0; + } + } + + virtual void set_active(bool active) override + { + if (active == get_active()) + return; + if (active) + m_xMenuButton->ExecuteMenu(); + else + m_xMenuButton->CancelMenu(); + } + + virtual bool get_active() const override { return m_xMenuButton->InPopupMode(); } + + virtual void set_inconsistent(bool /*inconsistent*/) override + { + //not available + } + + virtual bool get_inconsistent() const override { return false; } + + virtual void insert_item(int pos, const OUString& rId, const OUString& rStr, + const OUString* pIconName, VirtualDevice* pImageSurface, + TriState eCheckRadioFalse) override + { + m_nLastId = insert_to_menu(m_nLastId, m_xMenuButton->GetPopupMenu(), pos, rId, rStr, + pIconName, pImageSurface, eCheckRadioFalse); + } + + virtual void insert_separator(int pos, const OUString& rId) override + { + auto nInsertPos = pos == -1 ? MENU_APPEND : pos; + m_xMenuButton->GetPopupMenu()->InsertSeparator(rId.toUtf8(), nInsertPos); + } + + virtual void set_item_sensitive(const OString& rIdent, bool bSensitive) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->EnableItem(rIdent, bSensitive); + } + + virtual void remove_item(const OString& rId) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->RemoveItem(pMenu->GetItemPos(pMenu->GetItemId(rId))); + } + + virtual void clear() override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->Clear(); + } + + virtual void set_item_active(const OString& rIdent, bool bActive) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->CheckItem(rIdent, bActive); + } + + virtual void set_item_label(const OString& rIdent, const OUString& rText) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->SetItemText(pMenu->GetItemId(rIdent), rText); + } + + virtual OUString get_item_label(const OString& rIdent) const override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + return pMenu->GetItemText(pMenu->GetItemId(rIdent)); + } + + virtual void set_item_visible(const OString& rIdent, bool bShow) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->ShowItem(pMenu->GetItemId(rIdent), bShow); + } + + virtual void set_item_help_id(const OString& rIdent, const OString& rHelpId) override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + pMenu->SetHelpId(pMenu->GetItemId(rIdent), rHelpId); + } + + virtual OString get_item_help_id(const OString& rIdent) const override + { + PopupMenu* pMenu = m_xMenuButton->GetPopupMenu(); + return pMenu->GetHelpId(pMenu->GetItemId(rIdent)); + } + + virtual void set_popover(weld::Widget* pPopover) override + { + SalInstanceWidget* pPopoverWidget = dynamic_cast(pPopover); + m_xMenuButton->SetPopover(pPopoverWidget ? pPopoverWidget->getWidget() : nullptr); + } + + virtual ~SalInstanceMenuButton() override + { + m_xMenuButton->SetSelectHdl(Link<::MenuButton*, void>()); + m_xMenuButton->SetActivateHdl(Link<::MenuButton*, void>()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceMenuButton, MenuSelectHdl, ::MenuButton*, void) +{ + signal_selected(m_xMenuButton->GetCurItemIdent()); +} + +IMPL_LINK_NOARG(SalInstanceMenuButton, ActivateHdl, ::MenuButton*, void) +{ + if (notify_events_disabled()) + return; + signal_toggled(); +} + +namespace +{ +class SalInstanceLinkButton : public SalInstanceContainer, public virtual weld::LinkButton +{ +private: + VclPtr m_xButton; + Link m_aOrigClickHdl; + + DECL_LINK(ClickHdl, FixedHyperlink&, void); + +public: + SalInstanceLinkButton(FixedHyperlink* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceContainer(pButton, pBuilder, bTakeOwnership) + , m_xButton(pButton) + { + m_aOrigClickHdl = m_xButton->GetClickHdl(); + m_xButton->SetClickHdl(LINK(this, SalInstanceLinkButton, ClickHdl)); + } + + virtual void set_label(const OUString& rText) override { m_xButton->SetText(rText); } + + virtual OUString get_label() const override { return m_xButton->GetText(); } + + virtual void set_uri(const OUString& rUri) override { m_xButton->SetURL(rUri); } + + virtual OUString get_uri() const override { return m_xButton->GetURL(); } + + virtual ~SalInstanceLinkButton() override { m_xButton->SetClickHdl(m_aOrigClickHdl); } +}; + +} + +IMPL_LINK(SalInstanceLinkButton, ClickHdl, FixedHyperlink&, rButton, void) +{ + bool bConsumed = signal_activate_link(); + if (!bConsumed) + m_aOrigClickHdl.Call(rButton); +} + +namespace +{ +class SalInstanceRadioButton : public SalInstanceButton, public virtual weld::RadioButton +{ +private: + VclPtr<::RadioButton> m_xRadioButton; + + DECL_LINK(ToggleHdl, ::RadioButton&, void); + +public: + SalInstanceRadioButton(::RadioButton* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceButton(pButton, pBuilder, bTakeOwnership) + , m_xRadioButton(pButton) + { + m_xRadioButton->SetToggleHdl(LINK(this, SalInstanceRadioButton, ToggleHdl)); + } + + virtual void set_active(bool active) override + { + disable_notify_events(); + m_xRadioButton->Check(active); + enable_notify_events(); + } + + virtual bool get_active() const override { return m_xRadioButton->IsChecked(); } + + virtual void set_image(VirtualDevice* pDevice) override + { + m_xRadioButton->SetImageAlign(ImageAlign::Center); + if (pDevice) + m_xRadioButton->SetModeImage(createImage(*pDevice)); + else + m_xRadioButton->SetModeImage(Image()); + } + + virtual void set_image(const css::uno::Reference& rImage) override + { + m_xRadioButton->SetImageAlign(ImageAlign::Center); + m_xRadioButton->SetModeImage(Image(rImage)); + } + + virtual void set_from_icon_name(const OUString& rIconName) override + { + m_xRadioButton->SetModeRadioImage(Image(StockImage::Yes, rIconName)); + } + + virtual void set_inconsistent(bool /*inconsistent*/) override + { + //not available + } + + virtual bool get_inconsistent() const override { return false; } + + virtual ~SalInstanceRadioButton() override + { + m_xRadioButton->SetToggleHdl(Link<::RadioButton&, void>()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceRadioButton, ToggleHdl, ::RadioButton&, void) +{ + if (notify_events_disabled()) + return; + signal_toggled(); +} + +namespace +{ +class SalInstanceToggleButton : public SalInstanceButton, public virtual weld::ToggleButton +{ +private: + VclPtr m_xToggleButton; + + DECL_LINK(ToggleListener, VclWindowEvent&, void); + +public: + SalInstanceToggleButton(PushButton* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceButton(pButton, pBuilder, bTakeOwnership) + , m_xToggleButton(pButton) + { + } + + virtual void connect_toggled(const Link& rLink) override + { + assert(!m_aToggleHdl.IsSet()); + m_xToggleButton->AddEventListener(LINK(this, SalInstanceToggleButton, ToggleListener)); + weld::ToggleButton::connect_toggled(rLink); + } + + virtual void set_active(bool active) override + { + disable_notify_events(); + m_xToggleButton->Check(active); + enable_notify_events(); + } + + virtual bool get_active() const override { return m_xToggleButton->IsChecked(); } + + virtual void set_inconsistent(bool inconsistent) override + { + disable_notify_events(); + m_xToggleButton->SetState(inconsistent ? TRISTATE_INDET : TRISTATE_FALSE); + enable_notify_events(); + } + + virtual bool get_inconsistent() const override + { + return m_xToggleButton->GetState() == TRISTATE_INDET; + } + + virtual ~SalInstanceToggleButton() override + { + if (m_aToggleHdl.IsSet()) + m_xToggleButton->RemoveEventListener( + LINK(this, SalInstanceToggleButton, ToggleListener)); + } +}; + +} + +IMPL_LINK(SalInstanceToggleButton, ToggleListener, VclWindowEvent&, rEvent, void) +{ + if (notify_events_disabled()) + return; + if (rEvent.GetId() == VclEventId::PushbuttonToggle) + signal_toggled(); +} + +SalInstanceCheckButton::SalInstanceCheckButton(CheckBox* pButton, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceButton(pButton, pBuilder, bTakeOwnership) + , m_xCheckButton(pButton) +{ + m_xCheckButton->SetToggleHdl(LINK(this, SalInstanceCheckButton, ToggleHdl)); +} + +void SalInstanceCheckButton::set_active(bool active) +{ + disable_notify_events(); + m_xCheckButton->EnableTriState(false); + m_xCheckButton->Check(active); + enable_notify_events(); +} + +bool SalInstanceCheckButton::get_active() const { return m_xCheckButton->IsChecked(); } + +void SalInstanceCheckButton::set_inconsistent(bool inconsistent) +{ + disable_notify_events(); + m_xCheckButton->EnableTriState(true); + m_xCheckButton->SetState(inconsistent ? TRISTATE_INDET : TRISTATE_FALSE); + enable_notify_events(); +} + +bool SalInstanceCheckButton::get_inconsistent() const +{ + return m_xCheckButton->GetState() == TRISTATE_INDET; +} + +SalInstanceCheckButton::~SalInstanceCheckButton() +{ + m_xCheckButton->SetToggleHdl(Link()); +} + +IMPL_LINK_NOARG(SalInstanceCheckButton, ToggleHdl, CheckBox&, void) +{ + if (notify_events_disabled()) + return; + m_xCheckButton->EnableTriState(false); + signal_toggled(); +} + +namespace +{ +class SalInstanceScale : public SalInstanceWidget, public virtual weld::Scale +{ +private: + VclPtr m_xScale; + + DECL_LINK(SlideHdl, Slider*, void); + +public: + SalInstanceScale(Slider* pScale, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pScale, pBuilder, bTakeOwnership) + , m_xScale(pScale) + { + m_xScale->SetSlideHdl(LINK(this, SalInstanceScale, SlideHdl)); + } + + virtual void set_value(int value) override { m_xScale->SetThumbPos(value); } + + virtual void set_range(int min, int max) override + { + m_xScale->SetRangeMin(min); + m_xScale->SetRangeMax(max); + } + + virtual int get_value() const override { return m_xScale->GetThumbPos(); } + + virtual void set_increments(int step, int page) override + { + m_xScale->SetLineSize(step); + m_xScale->SetPageSize(page); + } + + virtual void get_increments(int& step, int& page) const override + { + step = m_xScale->GetLineSize(); + page = m_xScale->GetPageSize(); + } + + virtual ~SalInstanceScale() override { m_xScale->SetSlideHdl(Link()); } +}; + +} + +IMPL_LINK_NOARG(SalInstanceScale, SlideHdl, Slider*, void) { signal_value_changed(); } + +namespace +{ +class SalInstanceSpinner : public SalInstanceWidget, public virtual weld::Spinner +{ +private: + VclPtr m_xThrobber; + +public: + SalInstanceSpinner(Throbber* pThrobber, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pThrobber, pBuilder, bTakeOwnership) + , m_xThrobber(pThrobber) + { + } + + virtual void start() override { m_xThrobber->start(); } + + virtual void stop() override { m_xThrobber->stop(); } +}; + +class SalInstanceProgressBar : public SalInstanceWidget, public virtual weld::ProgressBar +{ +private: + VclPtr<::ProgressBar> m_xProgressBar; + +public: + SalInstanceProgressBar(::ProgressBar* pProgressBar, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceWidget(pProgressBar, pBuilder, bTakeOwnership) + , m_xProgressBar(pProgressBar) + { + } + + virtual void set_percentage(int value) override { m_xProgressBar->SetValue(value); } + + virtual OUString get_text() const override { return m_xProgressBar->GetText(); } + + virtual void set_text(const OUString& rText) override { m_xProgressBar->SetText(rText); } +}; + +class SalInstanceImage : public SalInstanceWidget, public virtual weld::Image +{ +private: + VclPtr m_xImage; + +public: + SalInstanceImage(FixedImage* pImage, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pImage, pBuilder, bTakeOwnership) + , m_xImage(pImage) + { + } + + virtual void set_from_icon_name(const OUString& rIconName) override + { + m_xImage->SetImage(::Image(StockImage::Yes, rIconName)); + } + + virtual void set_image(VirtualDevice* pDevice) override + { + if (pDevice) + m_xImage->SetImage(createImage(*pDevice)); + else + m_xImage->SetImage(::Image()); + } + + virtual void set_image(const css::uno::Reference& rImage) override + { + m_xImage->SetImage(::Image(rImage)); + } +}; + +class SalInstanceCalendar : public SalInstanceWidget, public virtual weld::Calendar +{ +private: + VclPtr<::Calendar> m_xCalendar; + + DECL_LINK(SelectHdl, ::Calendar*, void); + DECL_LINK(ActivateHdl, ::Calendar*, void); + +public: + SalInstanceCalendar(::Calendar* pCalendar, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pCalendar, pBuilder, bTakeOwnership) + , m_xCalendar(pCalendar) + { + m_xCalendar->SetSelectHdl(LINK(this, SalInstanceCalendar, SelectHdl)); + m_xCalendar->SetActivateHdl(LINK(this, SalInstanceCalendar, ActivateHdl)); + } + + virtual void set_date(const Date& rDate) override { m_xCalendar->SetCurDate(rDate); } + + virtual Date get_date() const override { return m_xCalendar->GetFirstSelectedDate(); } + + virtual ~SalInstanceCalendar() override + { + m_xCalendar->SetSelectHdl(Link<::Calendar*, void>()); + m_xCalendar->SetActivateHdl(Link<::Calendar*, void>()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceCalendar, SelectHdl, ::Calendar*, void) +{ + if (notify_events_disabled()) + return; + signal_selected(); +} + +IMPL_LINK_NOARG(SalInstanceCalendar, ActivateHdl, ::Calendar*, void) +{ + if (notify_events_disabled()) + return; + signal_activated(); +} + +WeldTextFilter::WeldTextFilter(Link& rInsertTextHdl) + : TextFilter(OUString()) + , m_rInsertTextHdl(rInsertTextHdl) +{ +} + +OUString WeldTextFilter::filter(const OUString& rText) +{ + if (!m_rInsertTextHdl.IsSet()) + return rText; + OUString sText(rText); + const bool bContinue = m_rInsertTextHdl.Call(sText); + if (!bContinue) + return OUString(); + return sText; +} + +SalInstanceEntry::SalInstanceEntry(Edit* pEntry, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceWidget(pEntry, pBuilder, bTakeOwnership) + , m_xEntry(pEntry) + , m_aTextFilter(m_aInsertTextHdl) +{ + m_xEntry->SetModifyHdl(LINK(this, SalInstanceEntry, ChangeHdl)); + m_xEntry->SetActivateHdl(LINK(this, SalInstanceEntry, ActivateHdl)); + m_xEntry->SetTextFilter(&m_aTextFilter); +} + +void SalInstanceEntry::set_text(const OUString& rText) +{ + disable_notify_events(); + m_xEntry->SetText(rText); + enable_notify_events(); +} + +OUString SalInstanceEntry::get_text() const +{ + return m_xEntry->GetText(); +} + +void SalInstanceEntry::set_width_chars(int nChars) +{ + m_xEntry->SetWidthInChars(nChars); +} + +int SalInstanceEntry::get_width_chars() const +{ + return m_xEntry->GetWidthInChars(); +} + +void SalInstanceEntry::set_max_length(int nChars) +{ + m_xEntry->SetMaxTextLen(nChars); +} + +void SalInstanceEntry::select_region(int nStartPos, int nEndPos) +{ + disable_notify_events(); + m_xEntry->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos)); + enable_notify_events(); +} + +bool SalInstanceEntry::get_selection_bounds(int& rStartPos, int& rEndPos) +{ + const Selection& rSelection = m_xEntry->GetSelection(); + rStartPos = rSelection.Min(); + rEndPos = rSelection.Max(); + return rSelection.Len(); +} + +void SalInstanceEntry::replace_selection(const OUString& rText) +{ + m_xEntry->ReplaceSelected(rText); +} + +void SalInstanceEntry::set_position(int nCursorPos) +{ + disable_notify_events(); + if (nCursorPos < 0) + m_xEntry->SetCursorAtLast(); + else + m_xEntry->SetSelection(Selection(nCursorPos, nCursorPos)); + enable_notify_events(); +} + +int SalInstanceEntry::get_position() const +{ + return m_xEntry->GetSelection().Max(); +} + +void SalInstanceEntry::set_editable(bool bEditable) +{ + m_xEntry->SetReadOnly(!bEditable); +} + +bool SalInstanceEntry::get_editable() const +{ + return !m_xEntry->IsReadOnly(); +} + +void SalInstanceEntry::set_message_type(weld::EntryMessageType eType) +{ + if (eType == weld::EntryMessageType::Error) + { + // tdf#114603: enable setting the background to a different color; + // relevant for GTK; see also #i75179# + m_xEntry->SetForceControlBackground(true); + m_xEntry->SetControlForeground(COL_WHITE); + m_xEntry->SetControlBackground(0xff6563); + } + else if (eType == weld::EntryMessageType::Warning) + { + // tdf#114603: enable setting the background to a different color; + // relevant for GTK; see also #i75179# + m_xEntry->SetForceControlBackground(true); + m_xEntry->SetControlForeground(); + m_xEntry->SetControlBackground(COL_YELLOW); + } + else + { + m_xEntry->SetForceControlBackground(false); + m_xEntry->SetControlForeground(); + m_xEntry->SetControlBackground(); + } +} + +void SalInstanceEntry::set_font(const vcl::Font& rFont) +{ + m_xEntry->SetPointFont(*m_xEntry, rFont); + m_xEntry->Invalidate(); +} + +void SalInstanceEntry::connect_cursor_position(const Link& rLink) +{ + assert(!m_aCursorPositionHdl.IsSet()); + m_xEntry->AddEventListener(LINK(this, SalInstanceEntry, CursorListener)); + weld::Entry::connect_cursor_position(rLink); +} + +void SalInstanceEntry::set_placeholder_text(const OUString& rText) +{ + m_xEntry->SetPlaceholderText(rText); +} + +Edit& SalInstanceEntry::getEntry() +{ + return *m_xEntry; +} + +void SalInstanceEntry::fire_signal_changed() +{ + signal_changed(); +} + +void SalInstanceEntry::cut_clipboard() +{ + m_xEntry->Cut(); +} + +void SalInstanceEntry::copy_clipboard() +{ + m_xEntry->Copy(); +} + +void SalInstanceEntry::paste_clipboard() +{ + m_xEntry->Paste(); +} + +SalInstanceEntry::~SalInstanceEntry() +{ + if (m_aCursorPositionHdl.IsSet()) + m_xEntry->RemoveEventListener(LINK(this, SalInstanceEntry, CursorListener)); + m_xEntry->SetTextFilter(nullptr); + m_xEntry->SetActivateHdl(Link()); + m_xEntry->SetModifyHdl(Link()); +} + +IMPL_LINK_NOARG(SalInstanceEntry, ChangeHdl, Edit&, void) { signal_changed(); } + +IMPL_LINK(SalInstanceEntry, CursorListener, VclWindowEvent&, rEvent, void) +{ + if (notify_events_disabled()) + return; + if (rEvent.GetId() == VclEventId::EditSelectionChanged + || rEvent.GetId() == VclEventId::EditCaretChanged) + signal_cursor_position(); +} + +IMPL_LINK_NOARG(SalInstanceEntry, ActivateHdl, Edit&, bool) { return m_aActivateHdl.Call(*this); } + +namespace +{ +struct SalInstanceTreeIter : public weld::TreeIter +{ + SalInstanceTreeIter(const SalInstanceTreeIter* pOrig) + : iter(pOrig ? pOrig->iter : nullptr) + { + } + SalInstanceTreeIter(SvTreeListEntry* pIter) + : iter(pIter) + { + } + virtual bool equal(const TreeIter& rOther) const override + { + return iter == static_cast(rOther).iter; + } + SvTreeListEntry* iter; +}; + +TriState get_toggle(SvTreeListEntry* pEntry, int col) +{ + ++col; //skip dummy/expander column + + if (static_cast(col) == pEntry->ItemCount()) + return TRISTATE_FALSE; + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + SvLBoxButton& rToggle = static_cast(rItem); + if (rToggle.IsStateTristate()) + return TRISTATE_INDET; + else if (rToggle.IsStateChecked()) + return TRISTATE_TRUE; + return TRISTATE_FALSE; +} + +bool get_text_emphasis(SvTreeListEntry* pEntry, int col) +{ + ++col; //skip dummy/expander column + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + return static_cast(rItem).IsEmphasized(); +} +} + +class SalInstanceTreeView; + +static SalInstanceTreeView* g_DragSource; + +namespace +{ + // tdf#131581 if the TreeView is hidden then there are possibly additional + // optimizations available + class UpdateGuardIfHidden + { + private: + SvTabListBox& m_rTreeView; + bool m_bOrigUpdate; + bool m_bOrigEnableInvalidate; + + public: + UpdateGuardIfHidden(SvTabListBox& rTreeView) + : m_rTreeView(rTreeView) + // tdf#136962 only do SetUpdateMode(false) optimization if the widget is currently hidden + , m_bOrigUpdate(!m_rTreeView.IsVisible() && m_rTreeView.IsUpdateMode()) + // tdf#137432 only do EnableInvalidate(false) optimization if the widget is currently hidden + , m_bOrigEnableInvalidate(!m_rTreeView.IsVisible() && m_rTreeView.GetModel()->IsEnableInvalidate()) + { + if (m_bOrigUpdate) + m_rTreeView.SetUpdateMode(false); + if (m_bOrigEnableInvalidate) + m_rTreeView.GetModel()->EnableInvalidate(false); + } + + ~UpdateGuardIfHidden() + { + if (m_bOrigEnableInvalidate) + m_rTreeView.GetModel()->EnableInvalidate(true); + if (m_bOrigUpdate) + m_rTreeView.SetUpdateMode(true); + } + }; +} + +class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::TreeView +{ +private: + // owner for UserData + std::vector> m_aUserData; + VclPtr m_xTreeView; + SvLBoxButtonData m_aCheckButtonData; + SvLBoxButtonData m_aRadioButtonData; + // currently expanding parent that logically, but not currently physically, + // contain placeholders + o3tl::sorted_vector m_aExpandingPlaceHolderParents; + // which columns should be custom rendered + o3tl::sorted_vector m_aCustomRenders; + bool m_bDisableCheckBoxAutoWidth; + int m_nSortColumn; + + DECL_LINK(SelectHdl, SvTreeListBox*, void); + DECL_LINK(DeSelectHdl, SvTreeListBox*, void); + DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool); + DECL_LINK(ExpandingHdl, SvTreeListBox*, bool); + DECL_LINK(EndDragHdl, HeaderBar*, void); + DECL_LINK(HeaderBarClickedHdl, HeaderBar*, void); + DECL_LINK(ToggleHdl, SvLBoxButtonData*, void); + DECL_LINK(ModelChangedHdl, SvTreeListBox*, void); + DECL_LINK(StartDragHdl, SvTreeListBox*, bool); + DECL_STATIC_LINK(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void); + DECL_LINK(EditingEntryHdl, SvTreeListEntry*, bool); + typedef std::pair IterString; + DECL_LINK(EditedEntryHdl, IterString, bool); + DECL_LINK(VisibleRangeChangedHdl, SvTreeListBox*, void); + DECL_LINK(CompareHdl, const SvSortData&, sal_Int32); + DECL_LINK(PopupMenuHdl, const CommandEvent&, bool); + DECL_LINK(TooltipHdl, const HelpEvent&, bool); + DECL_LINK(CustomRenderHdl, svtree_render_args, void); + DECL_LINK(CustomMeasureHdl, svtree_measure_args, Size); + + bool IsDummyEntry(SvTreeListEntry* pEntry) const + { + return m_xTreeView->GetEntryText(pEntry).trim() == ""; + } + + SvTreeListEntry* GetPlaceHolderChild(SvTreeListEntry* pEntry) const + { + if (pEntry->HasChildren()) + { + auto pChild = m_xTreeView->FirstChild(pEntry); + assert(pChild); + if (IsDummyEntry(pChild)) + return pChild; + } + return nullptr; + } + + static void set_font_color(SvTreeListEntry* pEntry, const Color& rColor) + { + if (rColor == COL_AUTO) + pEntry->SetTextColor(std::optional()); + else + pEntry->SetTextColor(rColor); + } + + void AddStringItem(SvTreeListEntry* pEntry, const OUString& rStr, int nCol) + { + auto xCell = std::make_unique(rStr); + if (m_aCustomRenders.count(nCol)) + xCell->SetCustomRender(); + pEntry->AddItem(std::move(xCell)); + } + + void InvalidateModelEntry(SvTreeListEntry* pEntry) + { + if (!m_xTreeView->GetModel()->IsEnableInvalidate()) + return; + m_xTreeView->ModelHasEntryInvalidated(pEntry); + } + +public: + SalInstanceTreeView(SvTabListBox* pTreeView, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pTreeView, pBuilder, bTakeOwnership) + , m_xTreeView(pTreeView) + , m_aCheckButtonData(pTreeView, false) + , m_aRadioButtonData(pTreeView, true) + , m_bDisableCheckBoxAutoWidth(false) + , m_nSortColumn(-1) + { + m_xTreeView->SetNodeDefaultImages(); + m_xTreeView->SetForceMakeVisible(true); + m_xTreeView->SetSelectHdl(LINK(this, SalInstanceTreeView, SelectHdl)); + m_xTreeView->SetDeselectHdl(LINK(this, SalInstanceTreeView, DeSelectHdl)); + m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl)); + m_xTreeView->SetExpandingHdl(LINK(this, SalInstanceTreeView, ExpandingHdl)); + m_xTreeView->SetPopupMenuHdl(LINK(this, SalInstanceTreeView, PopupMenuHdl)); + m_xTreeView->SetCustomRenderHdl(LINK(this, SalInstanceTreeView, CustomRenderHdl)); + m_xTreeView->SetCustomMeasureHdl(LINK(this, SalInstanceTreeView, CustomMeasureHdl)); + const long aTabPositions[] = { 0 }; + m_xTreeView->SetTabs(SAL_N_ELEMENTS(aTabPositions), aTabPositions); + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + + if (pHeaderBox) + { + if (HeaderBar* pHeaderBar = pHeaderBox->GetHeaderBar()) + { + //make the last entry fill available space + pHeaderBar->SetItemSize(pHeaderBar->GetItemId(pHeaderBar->GetItemCount() - 1), + HEADERBAR_FULLSIZE); + pHeaderBar->SetEndDragHdl(LINK(this, SalInstanceTreeView, EndDragHdl)); + pHeaderBar->SetSelectHdl(LINK(this, SalInstanceTreeView, HeaderBarClickedHdl)); + } + pHeaderBox->SetEditingEntryHdl(LINK(this, SalInstanceTreeView, EditingEntryHdl)); + pHeaderBox->SetEditedEntryHdl(LINK(this, SalInstanceTreeView, EditedEntryHdl)); + } + else + { + static_cast(*m_xTreeView) + .SetModelChangedHdl(LINK(this, SalInstanceTreeView, ModelChangedHdl)); + static_cast(*m_xTreeView) + .SetStartDragHdl(LINK(this, SalInstanceTreeView, StartDragHdl)); + static_cast(*m_xTreeView) + .SetEndDragHdl(LINK(this, SalInstanceTreeView, FinishDragHdl)); + static_cast(*m_xTreeView) + .SetEditingEntryHdl(LINK(this, SalInstanceTreeView, EditingEntryHdl)); + static_cast(*m_xTreeView) + .SetEditedEntryHdl(LINK(this, SalInstanceTreeView, EditedEntryHdl)); + } + m_aCheckButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl)); + m_aRadioButtonData.SetLink(LINK(this, SalInstanceTreeView, ToggleHdl)); + } + + virtual void connect_query_tooltip(const Link& rLink) override + { + weld::TreeView::connect_query_tooltip(rLink); + m_xTreeView->SetTooltipHdl(LINK(this, SalInstanceTreeView, TooltipHdl)); + } + + virtual void columns_autosize() override + { + std::vector aWidths; + m_xTreeView->getPreferredDimensions(aWidths); + if (aWidths.size() > 2) + { + std::vector aColWidths; + for (size_t i = 1; i < aWidths.size() - 1; ++i) + aColWidths.push_back(aWidths[i] - aWidths[i - 1]); + set_column_fixed_widths(aColWidths); + } + } + + virtual void freeze() override + { + SalInstanceWidget::freeze(); + m_xTreeView->SetUpdateMode(false); + } + + virtual void thaw() override + { + m_xTreeView->SetUpdateMode(true); + SalInstanceWidget::thaw(); + } + + virtual void set_column_fixed_widths(const std::vector& rWidths) override + { + m_bDisableCheckBoxAutoWidth = true; + std::vector aTabPositions; + aTabPositions.push_back(0); + for (size_t i = 0; i < rWidths.size(); ++i) + aTabPositions.push_back(aTabPositions[i] + rWidths[i]); + m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel); + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + for (size_t i = 0; i < rWidths.size(); ++i) + pHeaderBar->SetItemSize(pHeaderBar->GetItemId(i), rWidths[i]); + } + // call Resize to recalculate based on the new tabs + m_xTreeView->Resize(); + } + + virtual void set_column_editables(const std::vector& rEditables) override + { + size_t nTabCount = rEditables.size(); + for (size_t i = 0 ; i < nTabCount; ++i) + m_xTreeView->SetTabEditable(i, rEditables[i]); + } + + virtual void set_centered_column(int nCol) override + { + m_xTreeView->SetTabJustify(nCol, SvTabJustify::AdjustCenter); + } + + virtual int get_column_width(int nColumn) const override + { + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + return pHeaderBar->GetItemSize(pHeaderBar->GetItemId(nColumn)); + // GetTab(0) gives the position of the bitmap which is automatically inserted by the TabListBox. + // So the first text column's width is Tab(2)-Tab(1). + auto nWidthPixel + = m_xTreeView->GetLogicTab(nColumn + 2) - m_xTreeView->GetLogicTab(nColumn + 1); + nWidthPixel -= SV_TAB_BORDER; + return nWidthPixel; + } + + virtual OUString get_column_title(int nColumn) const override + { + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + return pHeaderBar->GetItemText(pHeaderBar->GetItemId(nColumn)); + } + return OUString(); + } + + virtual void set_column_title(int nColumn, const OUString& rTitle) override + { + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + return pHeaderBar->SetItemText(pHeaderBar->GetItemId(nColumn), rTitle); + } + } + + virtual void set_column_custom_renderer(int nColumn, bool bEnable) override + { + assert(n_children() == 0 && "tree must be empty"); + if (bEnable) + m_aCustomRenders.insert(nColumn); + else + m_aCustomRenders.erase(nColumn); + } + + virtual void show() override + { + if (LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get())) + pHeaderBox->GetParent()->Show(); + SalInstanceContainer::show(); + } + + virtual void hide() override + { + if (LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get())) + pHeaderBox->GetParent()->Hide(); + SalInstanceContainer::hide(); + } + + virtual void insert(const weld::TreeIter* pParent, int pos, const OUString* pStr, + const OUString* pId, const OUString* pIconName, + VirtualDevice* pImageSurface, const OUString* pExpanderName, + bool bChildrenOnDemand, weld::TreeIter* pRet) override + { + disable_notify_events(); + const SalInstanceTreeIter* pVclIter = static_cast(pParent); + SvTreeListEntry* iter = pVclIter ? pVclIter->iter : nullptr; + auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos; + void* pUserData; + if (pId) + { + m_aUserData.emplace_back(std::make_unique(*pId)); + pUserData = m_aUserData.back().get(); + } + else + pUserData = nullptr; + + SvTreeListEntry* pEntry = new SvTreeListEntry; + if (pIconName || pImageSurface) + { + Image aImage(pIconName ? createImage(*pIconName) : createImage(*pImageSurface)); + pEntry->AddItem(std::make_unique(aImage, aImage, false)); + } + else + { + Image aDummy; + pEntry->AddItem(std::make_unique(aDummy, aDummy, false)); + } + if (pStr) + AddStringItem(pEntry, *pStr, 0); + pEntry->SetUserData(pUserData); + m_xTreeView->Insert(pEntry, iter, nInsertPos); + + if (pExpanderName) + { + Image aImage(createImage(*pExpanderName)); + m_xTreeView->SetExpandedEntryBmp(pEntry, aImage); + m_xTreeView->SetCollapsedEntryBmp(pEntry, aImage); + } + + if (pRet) + { + SalInstanceTreeIter* pVclRetIter = static_cast(pRet); + pVclRetIter->iter = pEntry; + } + + if (bChildrenOnDemand) + { + SvTreeListEntry* pPlaceHolder = m_xTreeView->InsertEntry("", pEntry, false, 0, nullptr); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder); + pViewData->SetSelectable(false); + } + enable_notify_events(); + } + + virtual void + bulk_insert_for_each(int nSourceCount, + const std::function& func, + const std::vector* pFixedWidths) override + { + freeze(); + clear(); + SalInstanceTreeIter aVclIter(static_cast(nullptr)); + + m_xTreeView->nTreeFlags |= SvTreeFlags::MANINS; + + if (pFixedWidths) + set_column_fixed_widths(*pFixedWidths); + + Image aDummy; + for (int i = 0; i < nSourceCount; ++i) + { + aVclIter.iter = new SvTreeListEntry; + aVclIter.iter->AddItem(std::make_unique(aDummy, aDummy, false)); + m_xTreeView->Insert(aVclIter.iter, nullptr, TREELIST_APPEND); + func(aVclIter, i); + + if (!pFixedWidths) + continue; + + size_t nFixedWidths = std::min(pFixedWidths->size(), aVclIter.iter->ItemCount()); + for (size_t j = 0; j < nFixedWidths; ++j) + { + SvLBoxItem& rItem = aVclIter.iter->GetItem(j); + SvViewDataItem* pViewDataItem = m_xTreeView->GetViewDataItem(aVclIter.iter, &rItem); + pViewDataItem->mnWidth = (*pFixedWidths)[j]; + } + } + + m_xTreeView->nTreeFlags &= ~SvTreeFlags::MANINS; + + thaw(); + } + + virtual void set_font_color(int pos, const Color& rColor) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_font_color(pEntry, rColor); + } + + virtual void set_font_color(const weld::TreeIter& rIter, const Color& rColor) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_font_color(rVclIter.iter, rColor); + } + + virtual void remove(int pos) override + { + disable_notify_events(); + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + m_xTreeView->RemoveEntry(pEntry); + enable_notify_events(); + } + + virtual int find_text(const OUString& rText) const override + { + for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry; + pEntry = m_xTreeView->Next(pEntry)) + { + if (SvTabListBox::GetEntryText(pEntry, 0) == rText) + return SvTreeList::GetRelPos(pEntry); + } + return -1; + } + + virtual int find_id(const OUString& rId) const override + { + for (SvTreeListEntry* pEntry = m_xTreeView->First(); pEntry; + pEntry = m_xTreeView->Next(pEntry)) + { + const OUString* pId = static_cast(pEntry->GetUserData()); + if (!pId) + continue; + if (rId == *pId) + return SvTreeList::GetRelPos(pEntry); + } + return -1; + } + + virtual void swap(int pos1, int pos2) override + { + int min = std::min(pos1, pos2); + int max = std::max(pos1, pos2); + SvTreeList* pModel = m_xTreeView->GetModel(); + SvTreeListEntry* pEntry1 = pModel->GetEntry(nullptr, min); + SvTreeListEntry* pEntry2 = pModel->GetEntry(nullptr, max); + pModel->Move(pEntry1, pEntry2); + } + + virtual void clear() override + { + disable_notify_events(); + m_xTreeView->Clear(); + m_aUserData.clear(); + enable_notify_events(); + } + + virtual int n_children() const override + { + return m_xTreeView->GetModel()->GetChildList(nullptr).size(); + } + + virtual int iter_n_children(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return m_xTreeView->GetModel()->GetChildList(rVclIter.iter).size(); + } + + virtual void select(int pos) override + { + assert(m_xTreeView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + if (pos == -1 || (pos == 0 && n_children() == 0)) + m_xTreeView->SelectAll(false); + else + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + m_xTreeView->Select(pEntry, true); + m_xTreeView->MakeVisible(pEntry); + } + enable_notify_events(); + } + + virtual int get_cursor_index() const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry(); + if (!pEntry) + return -1; + return SvTreeList::GetRelPos(pEntry); + } + + virtual void set_cursor(int pos) override + { + disable_notify_events(); + if (pos == -1) + m_xTreeView->SetCurEntry(nullptr); + else + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + m_xTreeView->SetCurEntry(pEntry); + } + enable_notify_events(); + } + + virtual void scroll_to_row(int pos) override + { + assert(m_xTreeView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + m_xTreeView->MakeVisible(pEntry); + enable_notify_events(); + } + + virtual bool is_selected(int pos) const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + return m_xTreeView->IsSelected(pEntry); + } + + virtual void unselect(int pos) override + { + assert(m_xTreeView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + if (pos == -1) + m_xTreeView->SelectAll(true); + else + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + m_xTreeView->Select(pEntry, false); + } + enable_notify_events(); + } + + virtual std::vector get_selected_rows() const override + { + std::vector aRows; + + aRows.reserve(m_xTreeView->GetSelectionCount()); + for (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected(); pEntry; + pEntry = m_xTreeView->NextSelected(pEntry)) + aRows.push_back(SvTreeList::GetRelPos(pEntry)); + + return aRows; + } + + static OUString get_text(SvTreeListEntry* pEntry, int col) + { + if (col == -1) + return SvTabListBox::GetEntryText(pEntry, 0); + + ++col; //skip dummy/expander column + + if (static_cast(col) == pEntry->ItemCount()) + return OUString(); + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + return static_cast(rItem).GetText(); + } + + virtual OUString get_text(int pos, int col) const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + return get_text(pEntry, col); + } + + void set_text(SvTreeListEntry* pEntry, const OUString& rText, int col) + { + if (col == -1) + { + m_xTreeView->SetEntryText(pEntry, rText); + return; + } + + ++col; //skip dummy/expander column + + // blank out missing entries + for (int i = pEntry->ItemCount(); i < col; ++i) + AddStringItem(pEntry, "", i - 1); + + if (static_cast(col) == pEntry->ItemCount()) + { + AddStringItem(pEntry, rText, col - 1); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry); + m_xTreeView->InitViewData(pViewData, pEntry); + } + else + { + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + static_cast(rItem).SetText(rText); + } + InvalidateModelEntry(pEntry); + } + + virtual void set_text(int pos, const OUString& rText, int col) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_text(pEntry, rText, col); + } + + void set_sensitive(SvTreeListEntry* pEntry, bool bSensitive, int col) + { + if (col == -1) + { + auto nFlags = pEntry->GetFlags() & ~SvTLEntryFlags::SEMITRANSPARENT; + if (!bSensitive) + nFlags = nFlags | SvTLEntryFlags::SEMITRANSPARENT; + pEntry->SetFlags(nFlags); + const sal_uInt16 nCount = pEntry->ItemCount(); + for (sal_uInt16 nCur = 0; nCur < nCount; ++nCur) + { + SvLBoxItem& rItem = pEntry->GetItem(nCur); + if (rItem.GetType() == SvLBoxItemType::String) + { + rItem.Enable(bSensitive); + InvalidateModelEntry(pEntry); + break; + } + } + return; + } + + ++col; //skip dummy/expander column + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + rItem.Enable(bSensitive); + + InvalidateModelEntry(pEntry); + } + + using SalInstanceWidget::set_sensitive; + + virtual void set_sensitive(int pos, bool bSensitive, int col) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_sensitive(pEntry, bSensitive, col); + } + + virtual void set_sensitive(const weld::TreeIter& rIter, bool bSensitive, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_sensitive(rVclIter.iter, bSensitive, col); + } + + virtual TriState get_toggle(int pos, int col) const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + return ::get_toggle(pEntry, col); + } + + virtual TriState get_toggle(const weld::TreeIter& rIter, int col) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return ::get_toggle(rVclIter.iter, col); + } + + void set_toggle(SvTreeListEntry* pEntry, TriState eState, int col) + { + bool bRadio = std::find(m_aRadioIndexes.begin(), m_aRadioIndexes.end(), col) + != m_aRadioIndexes.end(); + ++col; //skip dummy/expander column + + // blank out missing entries + for (int i = pEntry->ItemCount(); i < col; ++i) + AddStringItem(pEntry, "", i - 1); + + if (static_cast(col) == pEntry->ItemCount()) + { + SvLBoxButtonData* pData = bRadio ? &m_aRadioButtonData : &m_aCheckButtonData; + + // if we want to have the implicit auto-sizing of the checkbox + // column we need to call EnableCheckButton and CheckBoxInserted to + // let it figure out that width. But we don't want to override any + // explicitly set column width, so disable this if we've set + // explicit column widths + if (!m_bDisableCheckBoxAutoWidth) + { + if (!(m_xTreeView->GetTreeFlags() & SvTreeFlags::CHKBTN)) + { + m_xTreeView->EnableCheckButton(pData); + // EnableCheckButton clobbered this, restore it + pData->SetLink(LINK(this, SalInstanceTreeView, ToggleHdl)); + } + } + + pEntry->AddItem(std::make_unique(pData)); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry); + m_xTreeView->InitViewData(pViewData, pEntry); + + if (!m_bDisableCheckBoxAutoWidth) + m_xTreeView->CheckBoxInserted(pEntry); + } + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + switch (eState) + { + case TRISTATE_TRUE: + static_cast(rItem).SetStateChecked(); + break; + case TRISTATE_FALSE: + static_cast(rItem).SetStateUnchecked(); + break; + case TRISTATE_INDET: + static_cast(rItem).SetStateTristate(); + break; + } + + InvalidateModelEntry(pEntry); + } + + virtual void set_toggle(int pos, TriState eState, int col) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_toggle(pEntry, eState, col); + } + + virtual void set_toggle(const weld::TreeIter& rIter, TriState eState, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_toggle(rVclIter.iter, eState, col); + } + + virtual void set_extra_row_indent(const weld::TreeIter& rIter, int nIndentLevel) override + { + weld::TreeIter& rNonConstIter = const_cast(rIter); + SalInstanceTreeIter& rVclIter = static_cast(rNonConstIter); + rVclIter.iter->SetExtraIndent(nIndentLevel); + } + + void set_text_emphasis(SvTreeListEntry* pEntry, bool bOn, int col) + { + ++col; //skip dummy/expander column + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + static_cast(rItem).Emphasize(bOn); + + InvalidateModelEntry(pEntry); + } + + virtual void set_text_emphasis(const weld::TreeIter& rIter, bool bOn, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_text_emphasis(rVclIter.iter, bOn, col); + } + + virtual void set_text_emphasis(int pos, bool bOn, int col) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_text_emphasis(pEntry, bOn, col); + } + + virtual bool get_text_emphasis(const weld::TreeIter& rIter, int col) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return ::get_text_emphasis(rVclIter.iter, col); + } + + virtual bool get_text_emphasis(int pos, int col) const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + return ::get_text_emphasis(pEntry, col); + } + + void set_text_align(SvTreeListEntry* pEntry, double fAlign, int col) + { + ++col; //skip dummy/expander column + + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + static_cast(rItem).Align(fAlign); + + InvalidateModelEntry(pEntry); + } + + virtual void set_text_align(const weld::TreeIter& rIter, double fAlign, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_text_align(rVclIter.iter, fAlign, col); + } + + virtual void set_text_align(int pos, double fAlign, int col) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_text_align(pEntry, fAlign, col); + } + + virtual void connect_editing( + const Link& rStartLink, + const Link&, bool>& rEndLink) override + { + m_xTreeView->EnableInplaceEditing(rStartLink.IsSet() || rEndLink.IsSet()); + weld::TreeView::connect_editing(rStartLink, rEndLink); + } + + virtual void start_editing(const weld::TreeIter& rIter) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xTreeView->EditEntry(rVclIter.iter); + } + + virtual void end_editing() override { m_xTreeView->EndEditing(); } + + void set_image(SvTreeListEntry* pEntry, const Image& rImage, int col) + { + if (col == -1) + { + m_xTreeView->SetExpandedEntryBmp(pEntry, rImage); + m_xTreeView->SetCollapsedEntryBmp(pEntry, rImage); + return; + } + + ++col; //skip dummy/expander column + + // blank out missing entries + for (int i = pEntry->ItemCount(); i < col; ++i) + AddStringItem(pEntry, "", i - 1); + + if (static_cast(col) == pEntry->ItemCount()) + { + pEntry->AddItem(std::make_unique(rImage, rImage, false)); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry); + m_xTreeView->InitViewData(pViewData, pEntry); + } + else + { + assert(col >= 0 && o3tl::make_unsigned(col) < pEntry->ItemCount()); + SvLBoxItem& rItem = pEntry->GetItem(col); + assert(dynamic_cast(&rItem)); + static_cast(rItem).SetBitmap1(rImage); + static_cast(rItem).SetBitmap2(rImage); + } + + m_xTreeView->SetEntryHeight(pEntry); + InvalidateModelEntry(pEntry); + } + + virtual void set_image(int pos, const OUString& rImage, int col) override + { + set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col); + } + + virtual void set_image(int pos, const css::uno::Reference& rImage, + int col) override + { + set_image(m_xTreeView->GetEntry(nullptr, pos), Image(rImage), col); + } + + virtual void set_image(int pos, VirtualDevice& rImage, int col) override + { + set_image(m_xTreeView->GetEntry(nullptr, pos), createImage(rImage), col); + } + + virtual void set_image(const weld::TreeIter& rIter, const OUString& rImage, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_image(rVclIter.iter, createImage(rImage), col); + } + + virtual void set_image(const weld::TreeIter& rIter, + const css::uno::Reference& rImage, + int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_image(rVclIter.iter, Image(rImage), col); + } + + virtual void set_image(const weld::TreeIter& rIter, VirtualDevice& rImage, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_image(rVclIter.iter, createImage(rImage), col); + } + + const OUString* getEntryData(int index) const + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, index); + return pEntry ? static_cast(pEntry->GetUserData()) : nullptr; + } + + virtual OUString get_id(int pos) const override + { + const OUString* pRet = getEntryData(pos); + if (!pRet) + return OUString(); + return *pRet; + } + + void set_id(SvTreeListEntry* pEntry, const OUString& rId) + { + m_aUserData.emplace_back(std::make_unique(rId)); + pEntry->SetUserData(m_aUserData.back().get()); + } + + virtual void set_id(int pos, const OUString& rId) override + { + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(nullptr, pos); + set_id(pEntry, rId); + } + + virtual int get_selected_index() const override + { + assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen"); + SvTreeListEntry* pEntry = m_xTreeView->FirstSelected(); + if (!pEntry) + return -1; + return SvTreeList::GetRelPos(pEntry); + } + + virtual OUString get_selected_text() const override + { + assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen"); + if (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected()) + return m_xTreeView->GetEntryText(pEntry); + return OUString(); + } + + virtual OUString get_selected_id() const override + { + assert(m_xTreeView->IsUpdateMode() && "don't request selection when frozen"); + if (SvTreeListEntry* pEntry = m_xTreeView->FirstSelected()) + { + if (const OUString* pStr = static_cast(pEntry->GetUserData())) + return *pStr; + } + return OUString(); + } + + virtual std::unique_ptr + make_iterator(const weld::TreeIter* pOrig) const override + { + return std::unique_ptr( + new SalInstanceTreeIter(static_cast(pOrig))); + } + + virtual void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const override + { + const SalInstanceTreeIter& rVclSource(static_cast(rSource)); + SalInstanceTreeIter& rVclDest(static_cast(rDest)); + rVclDest.iter = rVclSource.iter; + } + + virtual bool get_selected(weld::TreeIter* pIter) const override + { + SvTreeListEntry* pEntry = m_xTreeView->FirstSelected(); + auto pVclIter = static_cast(pIter); + if (pVclIter) + pVclIter->iter = pEntry; + return pEntry != nullptr; + } + + virtual bool get_cursor(weld::TreeIter* pIter) const override + { + SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry(); + auto pVclIter = static_cast(pIter); + if (pVclIter) + pVclIter->iter = pEntry; + return pEntry != nullptr; + } + + virtual void set_cursor(const weld::TreeIter& rIter) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + disable_notify_events(); + m_xTreeView->SetCurEntry(rVclIter.iter); + enable_notify_events(); + } + + virtual bool get_iter_first(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->GetEntry(0); + return rVclIter.iter != nullptr; + } + + virtual bool iter_next_sibling(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = rVclIter.iter->NextSibling(); + return rVclIter.iter != nullptr; + } + + virtual bool iter_previous_sibling(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = rVclIter.iter->PrevSibling(); + return rVclIter.iter != nullptr; + } + + virtual bool iter_next(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->Next(rVclIter.iter); + if (rVclIter.iter && IsDummyEntry(rVclIter.iter)) + return iter_next(rVclIter); + return rVclIter.iter != nullptr; + } + + virtual bool iter_previous(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->Prev(rVclIter.iter); + if (rVclIter.iter && IsDummyEntry(rVclIter.iter)) + return iter_previous(rVclIter); + return rVclIter.iter != nullptr; + } + + virtual bool iter_next_visible(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->NextVisible(rVclIter.iter); + if (rVclIter.iter && IsDummyEntry(rVclIter.iter)) + return iter_next_visible(rVclIter); + return rVclIter.iter != nullptr; + } + + virtual bool iter_children(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->FirstChild(rVclIter.iter); + bool bRet = rVclIter.iter != nullptr; + if (bRet) + { + //on-demand dummy entry doesn't count + return !IsDummyEntry(rVclIter.iter); + } + return bRet; + } + + virtual bool iter_parent(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xTreeView->GetParent(rVclIter.iter); + return rVclIter.iter != nullptr; + } + + virtual void remove(const weld::TreeIter& rIter) override + { + disable_notify_events(); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xTreeView->RemoveEntry(rVclIter.iter); + enable_notify_events(); + } + + virtual void select(const weld::TreeIter& rIter) override + { + assert(m_xTreeView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xTreeView->Select(rVclIter.iter, true); + enable_notify_events(); + } + + virtual void scroll_to_row(const weld::TreeIter& rIter) override + { + assert(m_xTreeView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xTreeView->MakeVisible(rVclIter.iter); + enable_notify_events(); + } + + virtual void unselect(const weld::TreeIter& rIter) override + { + assert(m_xTreeView->IsUpdateMode() && "don't unselect when frozen"); + disable_notify_events(); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xTreeView->Select(rVclIter.iter, false); + enable_notify_events(); + } + + virtual int get_iter_depth(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return m_xTreeView->GetModel()->GetDepth(rVclIter.iter); + } + + virtual bool iter_has_child(const weld::TreeIter& rIter) const override + { + weld::TreeIter& rNonConstIter = const_cast(rIter); + SalInstanceTreeIter& rVclIter = static_cast(rNonConstIter); + SvTreeListEntry* restore(rVclIter.iter); + bool ret = iter_children(rNonConstIter); + rVclIter.iter = restore; + return ret; + } + + virtual bool get_row_expanded(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return m_xTreeView->IsExpanded(rVclIter.iter); + } + + virtual bool get_children_on_demand(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + if (m_aExpandingPlaceHolderParents.count(rVclIter.iter)) + return true; + return GetPlaceHolderChild(rVclIter.iter) != nullptr; + } + + virtual void set_children_on_demand(const weld::TreeIter& rIter, bool bChildrenOnDemand) override + { + disable_notify_events(); + + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + + SvTreeListEntry* pPlaceHolder = GetPlaceHolderChild(rVclIter.iter); + + if (bChildrenOnDemand && !pPlaceHolder) + { + pPlaceHolder = m_xTreeView->InsertEntry("", rVclIter.iter, false, 0, nullptr); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder); + pViewData->SetSelectable(false); + } + else if (!bChildrenOnDemand && pPlaceHolder) + m_xTreeView->RemoveEntry(pPlaceHolder); + + enable_notify_events(); + } + + virtual void expand_row(const weld::TreeIter& rIter) override + { + assert(m_xTreeView->IsUpdateMode() && "don't expand when frozen"); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + if (!m_xTreeView->IsExpanded(rVclIter.iter) && signal_expanding(rIter)) + m_xTreeView->Expand(rVclIter.iter); + } + + virtual void collapse_row(const weld::TreeIter& rIter) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + if (m_xTreeView->IsExpanded(rVclIter.iter) && signal_collapsing(rIter)) + m_xTreeView->Collapse(rVclIter.iter); + } + + virtual OUString get_text(const weld::TreeIter& rIter, int col) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return get_text(rVclIter.iter, col); + } + + virtual void set_text(const weld::TreeIter& rIter, const OUString& rText, int col) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_text(rVclIter.iter, rText, col); + } + + virtual OUString get_id(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + const OUString* pStr = static_cast(rVclIter.iter->GetUserData()); + if (pStr) + return *pStr; + return OUString(); + } + + virtual void set_id(const weld::TreeIter& rIter, const OUString& rId) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + set_id(rVclIter.iter, rId); + } + + virtual void enable_drag_source(rtl::Reference& rHelper, + sal_uInt8 eDNDConstants) override + { + m_xTreeView->SetDragHelper(rHelper, eDNDConstants); + } + + virtual void set_selection_mode(SelectionMode eMode) override + { + m_xTreeView->SetSelectionMode(eMode); + } + + virtual void all_foreach(const std::function& func) override + { + UpdateGuardIfHidden aGuard(*m_xTreeView); + + SalInstanceTreeIter aVclIter(m_xTreeView->First()); + while (aVclIter.iter) + { + if (func(aVclIter)) + return; + iter_next(aVclIter); + } + } + + virtual void selected_foreach(const std::function& func) override + { + SalInstanceTreeIter aVclIter(m_xTreeView->FirstSelected()); + while (aVclIter.iter) + { + if (func(aVclIter)) + return; + aVclIter.iter = m_xTreeView->NextSelected(aVclIter.iter); + } + } + + virtual void visible_foreach(const std::function& func) override + { + SalInstanceTreeIter aVclIter(m_xTreeView->GetFirstEntryInView()); + while (aVclIter.iter) + { + if (func(aVclIter)) + return; + aVclIter.iter = m_xTreeView->GetNextEntryInView(aVclIter.iter); + } + } + + virtual void connect_visible_range_changed(const Link& rLink) override + { + weld::TreeView::connect_visible_range_changed(rLink); + m_xTreeView->SetScrolledHdl(LINK(this, SalInstanceTreeView, VisibleRangeChangedHdl)); + } + + virtual void remove_selection() override + { + disable_notify_events(); + SvTreeListEntry* pSelected = m_xTreeView->FirstSelected(); + while (pSelected) + { + SvTreeListEntry* pNextSelected = m_xTreeView->NextSelected(pSelected); + m_xTreeView->RemoveEntry(pSelected); + pSelected = pNextSelected; + } + enable_notify_events(); + } + + virtual bool is_selected(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return m_xTreeView->IsSelected(rVclIter.iter); + } + + virtual int get_iter_index_in_parent(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + return SvTreeList::GetRelPos(rVclIter.iter); + } + + virtual int iter_compare(const weld::TreeIter& a, const weld::TreeIter& b) const override + { + const SalInstanceTreeIter& rVclIterA = static_cast(a); + const SalInstanceTreeIter& rVclIterB = static_cast(b); + const SvTreeList* pModel = m_xTreeView->GetModel(); + auto nAbsPosA = pModel->GetAbsPos(rVclIterA.iter); + auto nAbsPosB = pModel->GetAbsPos(rVclIterB.iter); + if (nAbsPosA < nAbsPosB) + return -1; + if (nAbsPosA > nAbsPosB) + return 1; + return 0; + } + + virtual void move_subtree(weld::TreeIter& rNode, const weld::TreeIter* pNewParent, + int nIndexInNewParent) override + { + SalInstanceTreeIter& rVclIter = static_cast(rNode); + const SalInstanceTreeIter* pVclParentIter + = static_cast(pNewParent); + m_xTreeView->GetModel()->Move( + rVclIter.iter, pVclParentIter ? pVclParentIter->iter : nullptr, nIndexInNewParent); + } + + virtual int count_selected_rows() const override { return m_xTreeView->GetSelectionCount(); } + + virtual int get_height_rows(int nRows) const override + { + return m_xTreeView->GetEntryHeight() * nRows; + } + + virtual void make_sorted() override + { + assert(m_xTreeView->IsUpdateMode() && "don't sort when frozen"); + m_xTreeView->SetStyle(m_xTreeView->GetStyle() | WB_SORT); + m_xTreeView->GetModel()->SetCompareHdl(LINK(this, SalInstanceTreeView, CompareHdl)); + set_sort_order(true); + } + + virtual void set_sort_func( + const std::function& func) override + { + weld::TreeView::set_sort_func(func); + SvTreeList* pListModel = m_xTreeView->GetModel(); + pListModel->Resort(); + } + + virtual void make_unsorted() override + { + m_xTreeView->SetStyle(m_xTreeView->GetStyle() & ~WB_SORT); + } + + virtual void set_sort_order(bool bAscending) override + { + SvTreeList* pListModel = m_xTreeView->GetModel(); + pListModel->SetSortMode(bAscending ? SortAscending : SortDescending); + pListModel->Resort(); + } + + virtual bool get_sort_order() const override + { + return m_xTreeView->GetModel()->GetSortMode() == SortAscending; + } + + virtual void set_sort_indicator(TriState eState, int col) override + { + if (col == -1) + col = 0; + + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + sal_uInt16 nTextId = pHeaderBar->GetItemId(col); + HeaderBarItemBits nBits = pHeaderBar->GetItemBits(nTextId); + nBits &= ~HeaderBarItemBits::UPARROW; + nBits &= ~HeaderBarItemBits::DOWNARROW; + if (eState != TRISTATE_INDET) + { + if (eState == TRISTATE_TRUE) + nBits |= HeaderBarItemBits::DOWNARROW; + else + nBits |= HeaderBarItemBits::UPARROW; + } + pHeaderBar->SetItemBits(nTextId, nBits); + } + } + + virtual TriState get_sort_indicator(int col) const override + { + if (col == -1) + col = 0; + + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (HeaderBar* pHeaderBar = pHeaderBox ? pHeaderBox->GetHeaderBar() : nullptr) + { + sal_uInt16 nTextId = pHeaderBar->GetItemId(col); + HeaderBarItemBits nBits = pHeaderBar->GetItemBits(nTextId); + if (nBits & HeaderBarItemBits::DOWNARROW) + return TRISTATE_TRUE; + if (nBits & HeaderBarItemBits::UPARROW) + return TRISTATE_FALSE; + } + + return TRISTATE_INDET; + } + + virtual int get_sort_column() const override { return m_nSortColumn; } + + virtual void set_sort_column(int nColumn) override + { + if (nColumn == -1) + { + make_unsorted(); + m_nSortColumn = -1; + return; + } + + if (nColumn != m_nSortColumn) + { + m_nSortColumn = nColumn; + m_xTreeView->GetModel()->Resort(); + } + } + + SvTabListBox& getTreeView() { return *m_xTreeView; } + + virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult, bool bHighLightTarget) override + { + LclTabListBox* pTreeView = !bHighLightTarget ? dynamic_cast(m_xTreeView.get()) : nullptr; + SvTreeListEntry* pTarget = pTreeView ? pTreeView->GetTargetAtPoint(rPos, false) : m_xTreeView->GetDropTarget(rPos); + + if (pTarget && pResult) + { + SalInstanceTreeIter& rSalIter = static_cast(*pResult); + rSalIter.iter = pTarget; + } + + return pTarget != nullptr; + } + + virtual void unset_drag_dest_row() override + { + m_xTreeView->UnsetDropTarget(); + } + + virtual tools::Rectangle get_row_area(const weld::TreeIter& rIter) const override + { + return m_xTreeView->GetBoundingRect(static_cast(rIter).iter); + } + + virtual TreeView* get_drag_source() const override { return g_DragSource; } + + virtual int vadjustment_get_value() const override + { + int nValue = -1; + const SvTreeListEntry* pEntry = m_xTreeView->GetFirstEntryInView(); + if (pEntry) + nValue = m_xTreeView->GetAbsPos(pEntry); + return nValue; + } + + virtual void vadjustment_set_value(int nValue) override + { + if (nValue == -1) + return; + bool bUpdate = m_xTreeView->IsUpdateMode(); + if (bUpdate) + m_xTreeView->SetUpdateMode(false); + m_xTreeView->ScrollToAbsPos(nValue); + if (bUpdate) + m_xTreeView->SetUpdateMode(true); + } + + virtual ~SalInstanceTreeView() override + { + LclHeaderTabListBox* pHeaderBox = dynamic_cast(m_xTreeView.get()); + if (pHeaderBox) + { + if (HeaderBar* pHeaderBar = pHeaderBox->GetHeaderBar()) + { + pHeaderBar->SetSelectHdl(Link()); + pHeaderBar->SetEndDragHdl(Link()); + } + } + else + { + static_cast(*m_xTreeView).SetEndDragHdl(Link()); + static_cast(*m_xTreeView).SetStartDragHdl(Link()); + static_cast(*m_xTreeView) + .SetModelChangedHdl(Link()); + } + m_xTreeView->SetPopupMenuHdl(Link()); + m_xTreeView->SetExpandingHdl(Link()); + m_xTreeView->SetDoubleClickHdl(Link()); + m_xTreeView->SetSelectHdl(Link()); + m_xTreeView->SetDeselectHdl(Link()); + m_xTreeView->SetScrolledHdl(Link()); + m_xTreeView->SetTooltipHdl(Link()); + m_xTreeView->SetCustomRenderHdl(Link()); + m_xTreeView->SetCustomMeasureHdl(Link()); + } +}; + +IMPL_LINK(SalInstanceTreeView, TooltipHdl, const HelpEvent&, rHEvt, bool) +{ + if (notify_events_disabled()) + return false; + Point aPos(m_xTreeView->ScreenToOutputPixel(rHEvt.GetMousePosPixel())); + SvTreeListEntry* pEntry = m_xTreeView->GetEntry(aPos); + if (pEntry) + { + SalInstanceTreeIter aIter(pEntry); + OUString aTooltip = signal_query_tooltip(aIter); + if (aTooltip.isEmpty()) + return false; + Size aSize(m_xTreeView->GetOutputSizePixel().Width(), m_xTreeView->GetEntryHeight()); + tools::Rectangle aScreenRect( + m_xTreeView->OutputToScreenPixel(m_xTreeView->GetEntryPosition(pEntry)), aSize); + Help::ShowQuickHelp(m_xTreeView, aScreenRect, aTooltip); + } + return true; +} + +IMPL_LINK(SalInstanceTreeView, CustomRenderHdl, svtree_render_args, payload, void) +{ + vcl::RenderContext& rRenderDevice = std::get<0>(payload); + const tools::Rectangle& rRect = std::get<1>(payload); + const SvTreeListEntry& rEntry = std::get<2>(payload); + const OUString* pId = static_cast(rEntry.GetUserData()); + if (!pId) + return; + signal_custom_render(rRenderDevice, rRect, m_xTreeView->IsSelected(&rEntry), *pId); +} + +IMPL_LINK(SalInstanceTreeView, CustomMeasureHdl, svtree_measure_args, payload, Size) +{ + vcl::RenderContext& rRenderDevice = payload.first; + const SvTreeListEntry& rEntry = payload.second; + const OUString* pId = static_cast(rEntry.GetUserData()); + if (!pId) + return Size(); + return signal_custom_get_size(rRenderDevice, *pId); +} + +IMPL_LINK(SalInstanceTreeView, CompareHdl, const SvSortData&, rSortData, sal_Int32) +{ + const SvTreeListEntry* pLHS = rSortData.pLeft; + const SvTreeListEntry* pRHS = rSortData.pRight; + assert(pLHS && pRHS); + + if (m_aCustomSort) + return m_aCustomSort(SalInstanceTreeIter(const_cast(pLHS)), + SalInstanceTreeIter(const_cast(pRHS))); + + const SvLBoxString* pLeftTextItem; + const SvLBoxString* pRightTextItem; + + if (m_nSortColumn != -1) + { + size_t col = m_nSortColumn; + + ++col; //skip dummy/expander column + + if (col < pLHS->ItemCount()) + { + const SvLBoxString& rLeftTextItem + = static_cast(pLHS->GetItem(col)); + pLeftTextItem = &rLeftTextItem; + } + else + pLeftTextItem = nullptr; + if (col < pRHS->ItemCount()) + { + const SvLBoxString& rRightTextItem + = static_cast(pRHS->GetItem(col)); + pRightTextItem = &rRightTextItem; + } + else + pRightTextItem = nullptr; + } + else + { + pLeftTextItem + = static_cast(pLHS->GetFirstItem(SvLBoxItemType::String)); + pRightTextItem + = static_cast(pRHS->GetFirstItem(SvLBoxItemType::String)); + } + + return m_xTreeView->DefaultCompare(pLeftTextItem, pRightTextItem); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, VisibleRangeChangedHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + signal_visible_range_changed(); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, ModelChangedHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + signal_model_changed(); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, StartDragHdl, SvTreeListBox*, bool) +{ + bool bUnsetDragIcon(false); // ignored for vcl + if (m_aDragBeginHdl.Call(bUnsetDragIcon)) + return true; + g_DragSource = this; + return false; +} + +IMPL_STATIC_LINK_NOARG(SalInstanceTreeView, FinishDragHdl, SvTreeListBox*, void) +{ + g_DragSource = nullptr; +} + +IMPL_LINK(SalInstanceTreeView, ToggleHdl, SvLBoxButtonData*, pData, void) +{ + SvTreeListEntry* pEntry = pData->GetActEntry(); + SvLBoxButton* pBox = pData->GetActBox(); + + // tdf#122874 Select the row, calling SelectHdl, before handling + // the toggle + if (!m_xTreeView->IsSelected(pEntry)) + { + m_xTreeView->SelectAll(false); + m_xTreeView->Select(pEntry, true); + } + + // toggled signal handlers can query get_cursor to get which + // node was clicked + m_xTreeView->pImpl->m_pCursor = pEntry; + + for (int i = 1, nCount = pEntry->ItemCount(); i < nCount; ++i) + { + SvLBoxItem& rItem = pEntry->GetItem(i); + if (&rItem == pBox) + { + int nRow = SvTreeList::GetRelPos(pEntry); + int nCol = i - 1; // less dummy/expander column + signal_toggled(std::make_pair(nRow, nCol)); + break; + } + } +} + +IMPL_LINK_NOARG(SalInstanceTreeView, SelectHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + signal_changed(); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, DeSelectHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + if (m_xTreeView->GetSelectionMode() == SelectionMode::Single) + return; + signal_changed(); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, DoubleClickHdl, SvTreeListBox*, bool) +{ + if (notify_events_disabled()) + return false; + return !signal_row_activated(); +} + +IMPL_LINK(SalInstanceTreeView, EndDragHdl, HeaderBar*, pHeaderBar, void) +{ + std::vector aTabPositions; + aTabPositions.push_back(0); + for (int i = 0; i < pHeaderBar->GetItemCount() - 1; ++i) + aTabPositions.push_back(aTabPositions[i] + + pHeaderBar->GetItemSize(pHeaderBar->GetItemId(i))); + m_xTreeView->SetTabs(aTabPositions.size(), aTabPositions.data(), MapUnit::MapPixel); +} + +IMPL_LINK(SalInstanceTreeView, HeaderBarClickedHdl, HeaderBar*, pHeaderBar, void) +{ + sal_uInt16 nId = pHeaderBar->GetCurItemId(); + if (!(pHeaderBar->GetItemBits(nId) & HeaderBarItemBits::CLICKABLE)) + return; + signal_column_clicked(pHeaderBar->GetItemPos(nId)); +} + +IMPL_LINK_NOARG(SalInstanceTreeView, ExpandingHdl, SvTreeListBox*, bool) +{ + SvTreeListEntry* pEntry = m_xTreeView->GetHdlEntry(); + SalInstanceTreeIter aIter(pEntry); + + if (m_xTreeView->IsExpanded(pEntry)) + { + //collapsing; + return signal_collapsing(aIter); + } + + // expanding + + // if there's a preexisting placeholder child, required to make this + // potentially expandable in the first place, now we remove it + SvTreeListEntry* pPlaceHolder = GetPlaceHolderChild(pEntry); + if (pPlaceHolder) + { + m_aExpandingPlaceHolderParents.insert(pEntry); + m_xTreeView->RemoveEntry(pPlaceHolder); + } + + bool bRet = signal_expanding(aIter); + + if (pPlaceHolder) + { + //expand disallowed, restore placeholder + if (!bRet) + { + pPlaceHolder = m_xTreeView->InsertEntry("", pEntry, false, 0, nullptr); + SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder); + pViewData->SetSelectable(false); + } + m_aExpandingPlaceHolderParents.erase(pEntry); + } + + return bRet; +} + +IMPL_LINK(SalInstanceTreeView, PopupMenuHdl, const CommandEvent&, rEvent, bool) +{ + return m_aPopupMenuHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceTreeView, EditingEntryHdl, SvTreeListEntry*, pEntry, bool) +{ + return signal_editing_started(SalInstanceTreeIter(pEntry)); +} + +IMPL_LINK(SalInstanceTreeView, EditedEntryHdl, IterString, rIterString, bool) +{ + return signal_editing_done(std::pair( + SalInstanceTreeIter(rIterString.first), rIterString.second)); +} + +class SalInstanceIconView : public SalInstanceContainer, public virtual weld::IconView +{ +private: + // owner for UserData + std::vector> m_aUserData; + VclPtr<::IconView> m_xIconView; + + DECL_LINK(SelectHdl, SvTreeListBox*, void); + DECL_LINK(DeSelectHdl, SvTreeListBox*, void); + DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool); + +public: + SalInstanceIconView(::IconView* pIconView, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pIconView, pBuilder, bTakeOwnership) + , m_xIconView(pIconView) + { + m_xIconView->SetSelectHdl(LINK(this, SalInstanceIconView, SelectHdl)); + m_xIconView->SetDeselectHdl(LINK(this, SalInstanceIconView, DeSelectHdl)); + m_xIconView->SetDoubleClickHdl(LINK(this, SalInstanceIconView, DoubleClickHdl)); + } + + virtual void freeze() override + { + SalInstanceWidget::freeze(); + m_xIconView->SetUpdateMode(false); + } + + virtual void thaw() override + { + m_xIconView->SetUpdateMode(true); + SalInstanceWidget::thaw(); + } + + virtual void insert(int pos, const OUString* pStr, const OUString* pId, + const OUString* pIconName, weld::TreeIter* pRet) override + { + disable_notify_events(); + auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos; + void* pUserData; + if (pId) + { + m_aUserData.emplace_back(std::make_unique(*pId)); + pUserData = m_aUserData.back().get(); + } + else + pUserData = nullptr; + + SvTreeListEntry* pEntry = new SvTreeListEntry; + if (pIconName) + { + Image aImage(createImage(*pIconName)); + pEntry->AddItem(std::make_unique(aImage, aImage, false)); + } + else + { + Image aDummy; + pEntry->AddItem(std::make_unique(aDummy, aDummy, false)); + } + if (pStr) + pEntry->AddItem(std::make_unique(*pStr)); + pEntry->SetUserData(pUserData); + m_xIconView->Insert(pEntry, nullptr, nInsertPos); + + if (pRet) + { + SalInstanceTreeIter* pVclRetIter = static_cast(pRet); + pVclRetIter->iter = pEntry; + } + + enable_notify_events(); + } + + virtual OUString get_selected_id() const override + { + assert(m_xIconView->IsUpdateMode() && "don't request selection when frozen"); + if (SvTreeListEntry* pEntry = m_xIconView->FirstSelected()) + { + if (const OUString* pStr = static_cast(pEntry->GetUserData())) + return *pStr; + } + return OUString(); + } + + virtual OUString get_selected_text() const override + { + assert(m_xIconView->IsUpdateMode() && "don't request selection when frozen"); + if (SvTreeListEntry* pEntry = m_xIconView->FirstSelected()) + return m_xIconView->GetEntryText(pEntry); + return OUString(); + } + + virtual int count_selected_items() const override { return m_xIconView->GetSelectionCount(); } + + virtual void select(int pos) override + { + assert(m_xIconView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + if (pos == -1 || (pos == 0 && n_children() == 0)) + m_xIconView->SelectAll(false); + else + { + SvTreeListEntry* pEntry = m_xIconView->GetEntry(nullptr, pos); + m_xIconView->Select(pEntry, true); + m_xIconView->MakeVisible(pEntry); + } + enable_notify_events(); + } + + virtual void unselect(int pos) override + { + assert(m_xIconView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + if (pos == -1) + m_xIconView->SelectAll(true); + else + { + SvTreeListEntry* pEntry = m_xIconView->GetEntry(nullptr, pos); + m_xIconView->Select(pEntry, false); + } + enable_notify_events(); + } + + virtual int n_children() const override + { + return m_xIconView->GetModel()->GetChildList(nullptr).size(); + } + + virtual std::unique_ptr + make_iterator(const weld::TreeIter* pOrig) const override + { + return std::unique_ptr( + new SalInstanceTreeIter(static_cast(pOrig))); + } + + virtual bool get_selected(weld::TreeIter* pIter) const override + { + SvTreeListEntry* pEntry = m_xIconView->FirstSelected(); + auto pVclIter = static_cast(pIter); + if (pVclIter) + pVclIter->iter = pEntry; + return pEntry != nullptr; + } + + virtual bool get_cursor(weld::TreeIter* pIter) const override + { + SvTreeListEntry* pEntry = m_xIconView->GetCurEntry(); + auto pVclIter = static_cast(pIter); + if (pVclIter) + pVclIter->iter = pEntry; + return pEntry != nullptr; + } + + virtual void set_cursor(const weld::TreeIter& rIter) override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + disable_notify_events(); + m_xIconView->SetCurEntry(rVclIter.iter); + enable_notify_events(); + } + + virtual bool get_iter_first(weld::TreeIter& rIter) const override + { + SalInstanceTreeIter& rVclIter = static_cast(rIter); + rVclIter.iter = m_xIconView->GetEntry(0); + return rVclIter.iter != nullptr; + } + + virtual void scroll_to_item(const weld::TreeIter& rIter) override + { + assert(m_xIconView->IsUpdateMode() && "don't select when frozen, select after thaw. Note selection doesn't survive a freeze"); + disable_notify_events(); + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + m_xIconView->MakeVisible(rVclIter.iter); + enable_notify_events(); + } + + virtual void selected_foreach(const std::function& func) override + { + SalInstanceTreeIter aVclIter(m_xIconView->FirstSelected()); + while (aVclIter.iter) + { + if (func(aVclIter)) + return; + aVclIter.iter = m_xIconView->NextSelected(aVclIter.iter); + } + } + + virtual OUString get_id(const weld::TreeIter& rIter) const override + { + const SalInstanceTreeIter& rVclIter = static_cast(rIter); + const OUString* pStr = static_cast(rVclIter.iter->GetUserData()); + if (pStr) + return *pStr; + return OUString(); + } + + virtual void clear() override + { + disable_notify_events(); + m_xIconView->Clear(); + m_aUserData.clear(); + enable_notify_events(); + } + + virtual ~SalInstanceIconView() override + { + m_xIconView->SetDoubleClickHdl(Link()); + m_xIconView->SetSelectHdl(Link()); + m_xIconView->SetDeselectHdl(Link()); + } +}; + +IMPL_LINK_NOARG(SalInstanceIconView, SelectHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + signal_selection_changed(); +} + +IMPL_LINK_NOARG(SalInstanceIconView, DeSelectHdl, SvTreeListBox*, void) +{ + if (notify_events_disabled()) + return; + if (m_xIconView->GetSelectionMode() == SelectionMode::Single) + return; + signal_selection_changed(); +} + +IMPL_LINK_NOARG(SalInstanceIconView, DoubleClickHdl, SvTreeListBox*, bool) +{ + if (notify_events_disabled()) + return false; + return !signal_item_activated(); +} + +double SalInstanceSpinButton::toField(int nValue) const +{ + return static_cast(nValue) / Power10(get_digits()); + } + +int SalInstanceSpinButton::fromField(double fValue) const +{ + return FRound(fValue * Power10(get_digits())); +} + +SalInstanceSpinButton::SalInstanceSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceEntry(pButton, pBuilder, bTakeOwnership) + , m_xButton(pButton) +{ + m_xButton->SetThousandsSep(false); //off by default, MetricSpinButton enables it + m_xButton->SetUpHdl(LINK(this, SalInstanceSpinButton, UpDownHdl)); + m_xButton->SetDownHdl(LINK(this, SalInstanceSpinButton, UpDownHdl)); + m_xButton->SetLoseFocusHdl(LINK(this, SalInstanceSpinButton, LoseFocusHdl)); + m_xButton->SetOutputHdl(LINK(this, SalInstanceSpinButton, OutputHdl)); + m_xButton->SetInputHdl(LINK(this, SalInstanceSpinButton, InputHdl)); + if (Edit* pEdit = m_xButton->GetSubEdit()) + pEdit->SetActivateHdl(LINK(this, SalInstanceSpinButton, ActivateHdl)); + else + m_xButton->SetActivateHdl(LINK(this, SalInstanceSpinButton, ActivateHdl)); +} + +int SalInstanceSpinButton::get_value() const +{ + return fromField(m_xButton->GetValue()); + } + +void SalInstanceSpinButton::set_value(int value) +{ + m_xButton->SetValue(toField(value)); + } + +void SalInstanceSpinButton::set_range(int min, int max) +{ + m_xButton->SetMinValue(toField(min)); + m_xButton->SetMaxValue(toField(max)); +} + +void SalInstanceSpinButton::get_range(int& min, int& max) const +{ + min = fromField(m_xButton->GetMinValue()); + max = fromField(m_xButton->GetMaxValue()); +} + +void SalInstanceSpinButton::set_increments(int step, int /*page*/) +{ + m_xButton->SetSpinSize(toField(step)); +} + +void SalInstanceSpinButton::get_increments(int& step, int& page) const +{ + step = fromField(m_xButton->GetSpinSize()); + page = fromField(m_xButton->GetSpinSize()); +} + +void SalInstanceSpinButton::set_digits(unsigned int digits) +{ + m_xButton->SetDecimalDigits(digits); +} + +// SpinButton may be comprised of multiple subwidgets, consider the lot as +// one thing for focus +bool SalInstanceSpinButton::has_focus() const +{ + return m_xWidget->HasChildPathFocus(); +} + +//so with hh::mm::ss, incrementing mm will not reset ss +void SalInstanceSpinButton::DisableRemainderFactor() +{ + m_xButton->DisableRemainderFactor(); +} + +//off by default for direct SpinButtons, MetricSpinButton enables it +void SalInstanceSpinButton::SetUseThousandSep() +{ + m_xButton->SetThousandsSep(true); +} + +unsigned int SalInstanceSpinButton::get_digits() const +{ + return m_xButton->GetDecimalDigits(); +} + +SalInstanceSpinButton::~SalInstanceSpinButton() +{ + if (Edit* pEdit = m_xButton->GetSubEdit()) + pEdit->SetActivateHdl(Link()); + else + m_xButton->SetActivateHdl(Link()); + m_xButton->SetInputHdl(Link()); + m_xButton->SetOutputHdl(Link()); + m_xButton->SetLoseFocusHdl(Link()); + m_xButton->SetDownHdl(Link()); + m_xButton->SetUpHdl(Link()); +} + +IMPL_LINK_NOARG(SalInstanceSpinButton, ActivateHdl, Edit&, bool) +{ + // tdf#122348 return pressed to end dialog + signal_value_changed(); + return m_aActivateHdl.Call(*this); +} + +IMPL_LINK_NOARG(SalInstanceSpinButton, UpDownHdl, SpinField&, void) { signal_value_changed(); } + +IMPL_LINK_NOARG(SalInstanceSpinButton, LoseFocusHdl, Control&, void) { signal_value_changed(); } + +IMPL_LINK_NOARG(SalInstanceSpinButton, OutputHdl, Edit&, bool) { return signal_output(); } + +IMPL_LINK(SalInstanceSpinButton, InputHdl, sal_Int64*, pResult, TriState) +{ + int nResult; + TriState eRet = signal_input(&nResult); + if (eRet == TRISTATE_TRUE) + *pResult = nResult; + return eRet; +} + +namespace +{ +class SalInstanceFormattedSpinButton : public SalInstanceEntry, + public virtual weld::FormattedSpinButton +{ +private: + VclPtr m_xButton; + +public: + SalInstanceFormattedSpinButton(FormattedField* pButton, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceEntry(pButton, pBuilder, bTakeOwnership) + , m_xButton(pButton) + { + // #i6278# allow more decimal places than the output format. As + // the numbers shown in the edit fields are used for input, it makes more + // sense to display the values in the input format rather than the output + // format. + m_xButton->UseInputStringForFormatting(); + } + + virtual double get_value() const override { return m_xButton->GetValue(); } + + virtual void set_value(double value) override { m_xButton->SetValue(value); } + + virtual void set_range(double min, double max) override + { + m_xButton->SetMinValue(min); + m_xButton->SetMaxValue(max); + } + + virtual void get_range(double& min, double& max) const override + { + min = m_xButton->GetMinValue(); + max = m_xButton->GetMaxValue(); + } + + virtual void set_formatter(SvNumberFormatter* pFormatter) override + { + m_xButton->SetFormatter(pFormatter); + } + + virtual SvNumberFormatter* get_formatter() override { return m_xButton->GetFormatter(); } + + virtual sal_Int32 get_format_key() const override { return m_xButton->GetFormatKey(); } + + virtual void set_format_key(sal_Int32 nFormatKey) override + { + m_xButton->SetFormatKey(nFormatKey); + } + + virtual void treat_as_number(bool bSet) override { m_xButton->TreatAsNumber(bSet); } + + virtual void set_digits(unsigned int digits) override { m_xButton->SetDecimalDigits(digits); } +}; + +} + +SalInstanceLabel::SalInstanceLabel(Control* pLabel, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceWidget(pLabel, pBuilder, bTakeOwnership) + , m_xLabel(pLabel) +{ +} + +void SalInstanceLabel::set_label(const OUString& rText) { m_xLabel->SetText(rText); } + +OUString SalInstanceLabel::get_label() const { return m_xLabel->GetText(); } + +void SalInstanceLabel::set_mnemonic_widget(Widget* pTarget) +{ + FixedText* pLabel = dynamic_cast(m_xLabel.get()); + assert(pLabel && "can't use set_mnemonic_widget on SelectableFixedText"); + SalInstanceWidget* pTargetWidget = dynamic_cast(pTarget); + pLabel->set_mnemonic_widget(pTargetWidget ? pTargetWidget->getWidget() : nullptr); +} + +void SalInstanceLabel::set_message_type(weld::EntryMessageType eType) +{ + if (eType == weld::EntryMessageType::Error) + m_xLabel->SetControlBackground( + m_xLabel->GetSettings().GetStyleSettings().GetHighlightColor()); + else if (eType == weld::EntryMessageType::Warning) + m_xLabel->SetControlBackground(COL_YELLOW); + else + m_xLabel->SetControlBackground(); +} + +void SalInstanceLabel::set_font(const vcl::Font& rFont) +{ + m_xLabel->SetPointFont(*m_xLabel, rFont); + m_xLabel->Invalidate(); +} + +std::unique_ptr SalInstanceFrame::weld_label_widget() const +{ + FixedText* pLabel = dynamic_cast(m_xFrame->get_label_widget()); + if (!pLabel) + return nullptr; + return std::make_unique(pLabel, m_pBuilder, false); +} + +namespace +{ +class SalInstanceTextView : public SalInstanceContainer, public virtual weld::TextView +{ +private: + VclPtr m_xTextView; + Link m_aOrigVScrollHdl; + + DECL_LINK(ChangeHdl, Edit&, void); + DECL_LINK(VscrollHdl, ScrollBar*, void); + DECL_LINK(CursorListener, VclWindowEvent&, void); + +public: + SalInstanceTextView(VclMultiLineEdit* pTextView, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceContainer(pTextView, pBuilder, bTakeOwnership) + , m_xTextView(pTextView) + { + m_xTextView->SetModifyHdl(LINK(this, SalInstanceTextView, ChangeHdl)); + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + m_aOrigVScrollHdl = rVertScrollBar.GetScrollHdl(); + rVertScrollBar.SetScrollHdl(LINK(this, SalInstanceTextView, VscrollHdl)); + } + + virtual void set_text(const OUString& rText) override + { + disable_notify_events(); + m_xTextView->SetText(rText); + enable_notify_events(); + } + + virtual void replace_selection(const OUString& rText) override + { + disable_notify_events(); + m_xTextView->ReplaceSelected(rText); + enable_notify_events(); + } + + virtual OUString get_text() const override { return m_xTextView->GetText(); } + + bool get_selection_bounds(int& rStartPos, int& rEndPos) override + { + const Selection& rSelection = m_xTextView->GetSelection(); + rStartPos = rSelection.Min(); + rEndPos = rSelection.Max(); + return rSelection.Len(); + } + + virtual void select_region(int nStartPos, int nEndPos) override + { + disable_notify_events(); + m_xTextView->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos)); + enable_notify_events(); + } + + virtual void set_editable(bool bEditable) override { m_xTextView->SetReadOnly(!bEditable); } + + virtual void set_monospace(bool bMonospace) override + { + vcl::Font aOrigFont = m_xTextView->GetControlFont(); + vcl::Font aFont; + if (bMonospace) + aFont = OutputDevice::GetDefaultFont(DefaultFontType::UI_FIXED, LANGUAGE_DONTKNOW, + GetDefaultFontFlags::OnlyOne, m_xTextView); + else + aFont = Application::GetSettings().GetStyleSettings().GetFieldFont(); + aFont.SetFontHeight(aOrigFont.GetFontHeight()); + m_xTextView->SetFont(aFont); + m_xTextView->SetControlFont(aFont); + } + + virtual void connect_cursor_position(const Link& rLink) override + { + assert(!m_aCursorPositionHdl.IsSet()); + m_xTextView->AddEventListener(LINK(this, SalInstanceTextView, CursorListener)); + weld::TextView::connect_cursor_position(rLink); + } + + virtual int vadjustment_get_value() const override + { + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + return rVertScrollBar.GetThumbPos(); + } + + virtual void vadjustment_set_value(int value) override + { + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + rVertScrollBar.SetThumbPos(value); + m_aOrigVScrollHdl.Call(&rVertScrollBar); + } + + virtual int vadjustment_get_upper() const override + { + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + return rVertScrollBar.GetRangeMax(); + } + + virtual int vadjustment_get_lower() const override + { + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + return rVertScrollBar.GetRangeMin(); + } + + virtual int vadjustment_get_page_size() const override + { + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + return rVertScrollBar.GetVisibleSize(); + } + + virtual ~SalInstanceTextView() override + { + if (!m_xTextView->IsDisposed()) + { + if (m_aCursorPositionHdl.IsSet()) + m_xTextView->RemoveEventListener(LINK(this, SalInstanceTextView, CursorListener)); + m_xTextView->SetModifyHdl(Link()); + ScrollBar& rVertScrollBar = m_xTextView->GetVScrollBar(); + rVertScrollBar.SetScrollHdl(m_aOrigVScrollHdl); + } + } +}; + +} + +IMPL_LINK(SalInstanceTextView, VscrollHdl, ScrollBar*, pScrollBar, void) +{ + signal_vadjustment_changed(); + m_aOrigVScrollHdl.Call(pScrollBar); +} + +IMPL_LINK_NOARG(SalInstanceTextView, ChangeHdl, Edit&, void) { signal_changed(); } + +IMPL_LINK(SalInstanceTextView, CursorListener, VclWindowEvent&, rEvent, void) +{ + if (notify_events_disabled()) + return; + if (rEvent.GetId() == VclEventId::EditSelectionChanged + || rEvent.GetId() == VclEventId::EditCaretChanged) + signal_cursor_position(); +} + +namespace +{ +class SalInstanceExpander : public SalInstanceContainer, public virtual weld::Expander +{ +private: + VclPtr m_xExpander; + + DECL_LINK(ExpandedHdl, VclExpander&, void); + +public: + SalInstanceExpander(VclExpander* pExpander, SalInstanceBuilder* pBuilder, bool bTakeOwnership) + : SalInstanceContainer(pExpander, pBuilder, bTakeOwnership) + , m_xExpander(pExpander) + { + m_xExpander->SetExpandedHdl(LINK(this, SalInstanceExpander, ExpandedHdl)); + } + + virtual bool get_expanded() const override { return m_xExpander->get_expanded(); } + + virtual void set_expanded(bool bExpand) override { m_xExpander->set_expanded(bExpand); } + + virtual ~SalInstanceExpander() override + { + m_xExpander->SetExpandedHdl(Link()); + } +}; + +} + +IMPL_LINK_NOARG(SalInstanceExpander, ExpandedHdl, VclExpander&, void) { signal_expanded(); } + +namespace +{ +class SalInstanceDrawingArea : public SalInstanceWidget, public virtual weld::DrawingArea +{ +private: + VclPtr m_xDrawingArea; + + typedef std::pair target_and_area; + DECL_LINK(PaintHdl, target_and_area, void); + DECL_LINK(ResizeHdl, const Size&, void); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + DECL_LINK(MouseMoveHdl, const MouseEvent&, bool); + DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool); + DECL_LINK(KeyPressHdl, const KeyEvent&, bool); + DECL_LINK(KeyReleaseHdl, const KeyEvent&, bool); + DECL_LINK(StyleUpdatedHdl, VclDrawingArea&, void); + DECL_LINK(CommandHdl, const CommandEvent&, bool); + DECL_LINK(QueryTooltipHdl, tools::Rectangle&, OUString); + DECL_LINK(GetSurroundingHdl, OUString&, int); + DECL_LINK(StartDragHdl, VclDrawingArea*, bool); + + // SalInstanceWidget has a generic listener for all these + // events, ignore the ones we have specializations for + // in VclDrawingArea + virtual void HandleEventListener(VclWindowEvent& rEvent) override + { + if (rEvent.GetId() == VclEventId::WindowResize) + return; + SalInstanceWidget::HandleEventListener(rEvent); + } + + virtual void HandleMouseEventListener(VclSimpleEvent& rEvent) override + { + if (rEvent.GetId() == VclEventId::WindowMouseButtonDown + || rEvent.GetId() == VclEventId::WindowMouseButtonUp + || rEvent.GetId() == VclEventId::WindowMouseMove) + { + return; + } + SalInstanceWidget::HandleMouseEventListener(rEvent); + } + + virtual bool HandleKeyEventListener(VclWindowEvent& /*rEvent*/) override { return false; } + +public: + SalInstanceDrawingArea(VclDrawingArea* pDrawingArea, SalInstanceBuilder* pBuilder, + const a11yref& rAlly, FactoryFunction pUITestFactoryFunction, + void* pUserData, bool bTakeOwnership) + : SalInstanceWidget(pDrawingArea, pBuilder, bTakeOwnership) + , m_xDrawingArea(pDrawingArea) + { + m_xDrawingArea->SetAccessible(rAlly); + m_xDrawingArea->SetUITestFactory(std::move(pUITestFactoryFunction), pUserData); + m_xDrawingArea->SetPaintHdl(LINK(this, SalInstanceDrawingArea, PaintHdl)); + m_xDrawingArea->SetResizeHdl(LINK(this, SalInstanceDrawingArea, ResizeHdl)); + m_xDrawingArea->SetMousePressHdl(LINK(this, SalInstanceDrawingArea, MousePressHdl)); + m_xDrawingArea->SetMouseMoveHdl(LINK(this, SalInstanceDrawingArea, MouseMoveHdl)); + m_xDrawingArea->SetMouseReleaseHdl(LINK(this, SalInstanceDrawingArea, MouseReleaseHdl)); + m_xDrawingArea->SetKeyPressHdl(LINK(this, SalInstanceDrawingArea, KeyPressHdl)); + m_xDrawingArea->SetKeyReleaseHdl(LINK(this, SalInstanceDrawingArea, KeyReleaseHdl)); + m_xDrawingArea->SetStyleUpdatedHdl(LINK(this, SalInstanceDrawingArea, StyleUpdatedHdl)); + m_xDrawingArea->SetCommandHdl(LINK(this, SalInstanceDrawingArea, CommandHdl)); + m_xDrawingArea->SetQueryTooltipHdl(LINK(this, SalInstanceDrawingArea, QueryTooltipHdl)); + m_xDrawingArea->SetGetSurroundingHdl(LINK(this, SalInstanceDrawingArea, GetSurroundingHdl)); + m_xDrawingArea->SetStartDragHdl(LINK(this, SalInstanceDrawingArea, StartDragHdl)); + } + + virtual void queue_draw() override { m_xDrawingArea->Invalidate(); } + + virtual void queue_draw_area(int x, int y, int width, int height) override + { + m_xDrawingArea->Invalidate(tools::Rectangle(Point(x, y), Size(width, height))); + } + + virtual void queue_resize() override { m_xDrawingArea->queue_resize(); } + + virtual void connect_size_allocate(const Link& rLink) override + { + weld::Widget::connect_size_allocate(rLink); + } + + virtual void connect_key_press(const Link& rLink) override + { + weld::Widget::connect_key_press(rLink); + } + + virtual void connect_key_release(const Link& rLink) override + { + weld::Widget::connect_key_release(rLink); + } + + virtual void set_cursor(PointerStyle ePointerStyle) override + { + m_xDrawingArea->SetPointer(ePointerStyle); + } + + virtual void set_input_context(const InputContext& rInputContext) override + { + m_xDrawingArea->SetInputContext(rInputContext); + } + + virtual void im_context_set_cursor_location(const tools::Rectangle& rCursorRect, int nExtTextInputWidth) override + { + tools::Rectangle aCursorRect = m_xDrawingArea->PixelToLogic(rCursorRect); + m_xDrawingArea->SetCursorRect(&aCursorRect, m_xDrawingArea->PixelToLogic(Size(nExtTextInputWidth, 0)).Width()); + } + + virtual a11yref get_accessible_parent() override + { + vcl::Window* pParent = m_xDrawingArea->GetParent(); + if (pParent) + return pParent->GetAccessible(); + return css::uno::Reference(); + } + + virtual a11yrelationset get_accessible_relation_set() override + { + utl::AccessibleRelationSetHelper* pRelationSetHelper = new utl::AccessibleRelationSetHelper; + css::uno::Reference xSet = pRelationSetHelper; + vcl::Window* pWindow = m_xDrawingArea.get(); + if (pWindow) + { + vcl::Window* pLabeledBy = pWindow->GetAccessibleRelationLabeledBy(); + if (pLabeledBy && pLabeledBy != pWindow) + { + css::uno::Sequence> aSequence{ + pLabeledBy->GetAccessible() + }; + pRelationSetHelper->AddRelation(css::accessibility::AccessibleRelation( + css::accessibility::AccessibleRelationType::LABELED_BY, aSequence)); + } + vcl::Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf(); + if (pMemberOf && pMemberOf != pWindow) + { + css::uno::Sequence> aSequence{ + pMemberOf->GetAccessible() + }; + pRelationSetHelper->AddRelation(css::accessibility::AccessibleRelation( + css::accessibility::AccessibleRelationType::MEMBER_OF, aSequence)); + } + } + return xSet; + } + + virtual Point get_accessible_location() override + { + return m_xDrawingArea->OutputToAbsoluteScreenPixel(Point()); + } + + virtual void enable_drag_source(rtl::Reference& rHelper, + sal_uInt8 eDNDConstants) override + { + m_xDrawingArea->SetDragHelper(rHelper, eDNDConstants); + } + + virtual ~SalInstanceDrawingArea() override + { + m_xDrawingArea->SetGetSurroundingHdl(Link()); + m_xDrawingArea->SetQueryTooltipHdl(Link()); + m_xDrawingArea->SetCommandHdl(Link()); + m_xDrawingArea->SetStyleUpdatedHdl(Link()); + m_xDrawingArea->SetMousePressHdl(Link()); + m_xDrawingArea->SetMouseMoveHdl(Link()); + m_xDrawingArea->SetMouseReleaseHdl(Link()); + m_xDrawingArea->SetKeyPressHdl(Link()); + m_xDrawingArea->SetKeyReleaseHdl(Link()); + m_xDrawingArea->SetResizeHdl(Link()); + m_xDrawingArea->SetPaintHdl( + Link, void>()); + } + + virtual OutputDevice& get_ref_device() override { return *m_xDrawingArea; } +}; + +} + +IMPL_LINK(SalInstanceDrawingArea, PaintHdl, target_and_area, aPayload, void) +{ + m_aDrawHdl.Call(aPayload); + tools::Rectangle aFocusRect(m_aGetFocusRectHdl.Call(*this)); + if (!aFocusRect.IsEmpty()) + DrawFocusRect(aPayload.first, aFocusRect); +} + +IMPL_LINK(SalInstanceDrawingArea, ResizeHdl, const Size&, rSize, void) +{ + m_aSizeAllocateHdl.Call(rSize); +} + +IMPL_LINK(SalInstanceDrawingArea, MousePressHdl, const MouseEvent&, rEvent, bool) +{ + return m_aMousePressHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceDrawingArea, MouseMoveHdl, const MouseEvent&, rEvent, bool) +{ + return m_aMouseMotionHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceDrawingArea, MouseReleaseHdl, const MouseEvent&, rEvent, bool) +{ + return m_aMouseReleaseHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceDrawingArea, KeyPressHdl, const KeyEvent&, rEvent, bool) +{ + return m_aKeyPressHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceDrawingArea, KeyReleaseHdl, const KeyEvent&, rEvent, bool) +{ + return m_aKeyReleaseHdl.Call(rEvent); +} + +IMPL_LINK_NOARG(SalInstanceDrawingArea, StyleUpdatedHdl, VclDrawingArea&, void) +{ + m_aStyleUpdatedHdl.Call(*this); +} + +IMPL_LINK(SalInstanceDrawingArea, CommandHdl, const CommandEvent&, rEvent, bool) +{ + return m_aCommandHdl.Call(rEvent); +} + +IMPL_LINK(SalInstanceDrawingArea, GetSurroundingHdl, OUString&, rSurrounding, int) +{ + return m_aGetSurroundingHdl.Call(rSurrounding); +} + +IMPL_LINK(SalInstanceDrawingArea, QueryTooltipHdl, tools::Rectangle&, rHelpArea, OUString) +{ + return m_aQueryTooltipHdl.Call(rHelpArea); +} + +IMPL_LINK_NOARG(SalInstanceDrawingArea, StartDragHdl, VclDrawingArea*, bool) +{ + if (m_aDragBeginHdl.Call(*this)) + return true; + return false; +} + +SalInstanceComboBoxWithoutEdit::SalInstanceComboBoxWithoutEdit(ListBox* pListBox, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceComboBox(pListBox, pBuilder, bTakeOwnership) +{ + m_xComboBox->SetSelectHdl(LINK(this, SalInstanceComboBoxWithoutEdit, SelectHdl)); +} + +OUString SalInstanceComboBoxWithoutEdit::get_active_text() const { return m_xComboBox->GetSelectedEntry(); } + +void SalInstanceComboBoxWithoutEdit::remove(int pos) { m_xComboBox->RemoveEntry(pos); } + +void SalInstanceComboBoxWithoutEdit::insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) +{ + auto nInsertPos = pos == -1 ? COMBOBOX_APPEND : pos; + sal_Int32 nInsertedAt; + if (!pIconName && !pImageSurface) + nInsertedAt = m_xComboBox->InsertEntry(rStr, nInsertPos); + else if (pIconName) + nInsertedAt = m_xComboBox->InsertEntry(rStr, createImage(*pIconName), nInsertPos); + else + nInsertedAt = m_xComboBox->InsertEntry(rStr, createImage(*pImageSurface), nInsertPos); + if (pId) + { + m_aUserData.emplace_back(std::make_unique(*pId)); + m_xComboBox->SetEntryData(nInsertedAt, m_aUserData.back().get()); + } +} + +void SalInstanceComboBoxWithoutEdit::insert_separator(int pos, const OUString& /*rId*/) +{ + auto nInsertPos = pos == -1 ? m_xComboBox->GetEntryCount() : pos; + m_xComboBox->AddSeparator(nInsertPos - 1); +} + +bool SalInstanceComboBoxWithoutEdit::has_entry() const { return false; } + +bool SalInstanceComboBoxWithoutEdit::changed_by_direct_pick() const { return true; } + +void SalInstanceComboBoxWithoutEdit::set_entry_message_type(weld::EntryMessageType /*eType*/) +{ + assert(false); +} + +void SalInstanceComboBoxWithoutEdit::set_entry_text(const OUString& /*rText*/) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::select_entry_region(int /*nStartPos*/, int /*nEndPos*/) { assert(false); } + +bool SalInstanceComboBoxWithoutEdit::get_entry_selection_bounds(int& /*rStartPos*/, int& /*rEndPos*/) +{ + assert(false); + return false; +} + +void SalInstanceComboBoxWithoutEdit::set_entry_width_chars(int /*nChars*/) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::set_entry_max_length(int /*nChars*/) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::set_entry_completion(bool, bool) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::set_entry_placeholder_text(const OUString&) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::set_entry_editable(bool /*bEditable*/) { assert(false); } + +void SalInstanceComboBoxWithoutEdit::cut_entry_clipboard() { assert(false); } + +void SalInstanceComboBoxWithoutEdit::copy_entry_clipboard() { assert(false); } + +void SalInstanceComboBoxWithoutEdit::paste_entry_clipboard() { assert(false); } + +void SalInstanceComboBoxWithoutEdit::set_entry_font(const vcl::Font&) { assert(false); } + +vcl::Font SalInstanceComboBoxWithoutEdit::get_entry_font() { assert(false); return vcl::Font(); } + +void SalInstanceComboBoxWithoutEdit::set_custom_renderer(bool /*bOn*/) +{ + assert(false && "not implemented"); +} + +int SalInstanceComboBoxWithoutEdit::get_max_mru_count() const +{ + assert(false && "not implemented"); + return 0; +} + +void SalInstanceComboBoxWithoutEdit::set_max_mru_count(int) +{ + assert(false && "not implemented"); +} + +OUString SalInstanceComboBoxWithoutEdit::get_mru_entries() const +{ + assert(false && "not implemented"); + return OUString(); +} + +void SalInstanceComboBoxWithoutEdit::set_mru_entries(const OUString&) +{ + assert(false && "not implemented"); +} + +void SalInstanceComboBoxWithoutEdit::HandleEventListener(VclWindowEvent& rEvent) +{ + CallHandleEventListener(rEvent); +} + +SalInstanceComboBoxWithoutEdit::~SalInstanceComboBoxWithoutEdit() +{ + m_xComboBox->SetSelectHdl(Link()); +} + +IMPL_LINK_NOARG(SalInstanceComboBoxWithoutEdit, SelectHdl, ListBox&, void) +{ + return signal_changed(); +} + +SalInstanceComboBoxWithEdit::SalInstanceComboBoxWithEdit(::ComboBox* pComboBox, SalInstanceBuilder* pBuilder, + bool bTakeOwnership) + : SalInstanceComboBox<::ComboBox>(pComboBox, pBuilder, bTakeOwnership) + , m_aTextFilter(m_aEntryInsertTextHdl) + , m_bInSelect(false) +{ + m_xComboBox->SetModifyHdl(LINK(this, SalInstanceComboBoxWithEdit, ChangeHdl)); + m_xComboBox->SetSelectHdl(LINK(this, SalInstanceComboBoxWithEdit, SelectHdl)); + m_xComboBox->SetEntryActivateHdl(LINK(this, SalInstanceComboBoxWithEdit, EntryActivateHdl)); + m_xComboBox->SetTextFilter(&m_aTextFilter); +} + +bool SalInstanceComboBoxWithEdit::has_entry() const { return true; } + +bool SalInstanceComboBoxWithEdit::changed_by_direct_pick() const +{ + return m_bInSelect && !m_xComboBox->IsModifyByKeyboard() && !m_xComboBox->IsTravelSelect(); +} + +void SalInstanceComboBoxWithEdit::set_entry_message_type(weld::EntryMessageType eType) +{ + if (eType == weld::EntryMessageType::Error) + m_xComboBox->SetControlForeground(Color(0xf0, 0, 0)); + else if (eType == weld::EntryMessageType::Warning) + m_xComboBox->SetControlForeground(COL_YELLOW); + else + m_xComboBox->SetControlForeground(); +} + +OUString SalInstanceComboBoxWithEdit::get_active_text() const { return m_xComboBox->GetText(); } + +void SalInstanceComboBoxWithEdit::remove(int pos) { m_xComboBox->RemoveEntryAt(pos); } + +void SalInstanceComboBoxWithEdit::insert(int pos, const OUString& rStr, const OUString* pId, + const OUString* pIconName, VirtualDevice* pImageSurface) +{ + auto nInsertPos = pos == -1 ? COMBOBOX_APPEND : pos; + sal_Int32 nInsertedAt; + if (!pIconName && !pImageSurface) + nInsertedAt = m_xComboBox->InsertEntry(rStr, nInsertPos); + else if (pIconName) + nInsertedAt + = m_xComboBox->InsertEntryWithImage(rStr, createImage(*pIconName), nInsertPos); + else + nInsertedAt + = m_xComboBox->InsertEntryWithImage(rStr, createImage(*pImageSurface), nInsertPos); + if (pId) + { + m_aUserData.emplace_back(std::make_unique(*pId)); + m_xComboBox->SetEntryData(nInsertedAt, m_aUserData.back().get()); + } +} + +void SalInstanceComboBoxWithEdit::insert_separator(int pos, const OUString& /*rId*/) +{ + auto nInsertPos = pos == -1 ? m_xComboBox->GetEntryCount() : pos; + m_xComboBox->AddSeparator(nInsertPos - 1); +} + +void SalInstanceComboBoxWithEdit::set_entry_text(const OUString& rText) { m_xComboBox->SetText(rText); } + +void SalInstanceComboBoxWithEdit::set_entry_width_chars(int nChars) +{ + m_xComboBox->SetWidthInChars(nChars); +} + +void SalInstanceComboBoxWithEdit::set_entry_max_length(int nChars) { m_xComboBox->SetMaxTextLen(nChars); } + +void SalInstanceComboBoxWithEdit::set_entry_completion(bool bEnable, bool bCaseSensitive) +{ + m_xComboBox->EnableAutocomplete(bEnable, bCaseSensitive); +} + +void SalInstanceComboBoxWithEdit::set_entry_placeholder_text(const OUString& rText) +{ + m_xComboBox->SetPlaceholderText(rText); +} + +void SalInstanceComboBoxWithEdit::set_entry_editable(bool bEditable) +{ + m_xComboBox->SetReadOnly(!bEditable); +} + +void SalInstanceComboBoxWithEdit::cut_entry_clipboard() +{ + m_xComboBox->Cut(); +} + +void SalInstanceComboBoxWithEdit::copy_entry_clipboard() +{ + m_xComboBox->Copy(); +} + +void SalInstanceComboBoxWithEdit::paste_entry_clipboard() +{ + m_xComboBox->Paste(); +} + +void SalInstanceComboBoxWithEdit::select_entry_region(int nStartPos, int nEndPos) +{ + m_xComboBox->SetSelection(Selection(nStartPos, nEndPos < 0 ? SELECTION_MAX : nEndPos)); +} + +bool SalInstanceComboBoxWithEdit::get_entry_selection_bounds(int& rStartPos, int& rEndPos) +{ + const Selection& rSelection = m_xComboBox->GetSelection(); + rStartPos = rSelection.Min(); + rEndPos = rSelection.Max(); + return rSelection.Len(); +} + +void SalInstanceComboBoxWithEdit::set_entry_font(const vcl::Font& rFont) +{ + Edit* pEdit = m_xComboBox->GetSubEdit(); + assert(pEdit); + pEdit->SetPointFont(*pEdit, rFont); + m_xComboBox->SetControlFont(rFont); // tdf#134601 set it as control font to take effect properly + pEdit->Invalidate(); +} + +vcl::Font SalInstanceComboBoxWithEdit::get_entry_font() +{ + Edit* pEdit = m_xComboBox->GetSubEdit(); + assert(pEdit); + return pEdit->GetPointFont(*pEdit); +} + +void SalInstanceComboBoxWithEdit::set_custom_renderer(bool bOn) +{ + if (m_xComboBox->IsUserDrawEnabled() == bOn) + return; + + auto nOldEntryHeight = m_xComboBox->GetDropDownEntryHeight(); + auto nDropDownLineCount = m_xComboBox->GetDropDownLineCount(); + + m_xComboBox->EnableUserDraw(bOn); + if (bOn) + m_xComboBox->SetUserDrawHdl(LINK(this, SalInstanceComboBoxWithEdit, UserDrawHdl)); + else + m_xComboBox->SetUserDrawHdl(Link()); + + // adjust the line count to fit approx the height it would have been before + // changing the renderer + auto nNewEntryHeight = m_xComboBox->GetDropDownEntryHeight(); + double fRatio = nOldEntryHeight / static_cast(nNewEntryHeight); + m_xComboBox->SetDropDownLineCount(nDropDownLineCount * fRatio); +} + +int SalInstanceComboBoxWithEdit::get_max_mru_count() const +{ + return m_xComboBox->GetMaxMRUCount(); +} + +void SalInstanceComboBoxWithEdit::set_max_mru_count(int nCount) +{ + return m_xComboBox->SetMaxMRUCount(nCount); +} + +OUString SalInstanceComboBoxWithEdit::get_mru_entries() const +{ + return m_xComboBox->GetMRUEntries(); +} + +void SalInstanceComboBoxWithEdit::set_mru_entries(const OUString& rEntries) +{ + m_xComboBox->SetMRUEntries(rEntries); +} + +void SalInstanceComboBoxWithEdit::HandleEventListener(VclWindowEvent& rEvent) +{ + if (rEvent.GetId() == VclEventId::DropdownPreOpen) + { + Size aRowSize(signal_custom_get_size(*m_xComboBox)); + m_xComboBox->SetUserItemSize(aRowSize); + } + CallHandleEventListener(rEvent); +} + +SalInstanceComboBoxWithEdit::~SalInstanceComboBoxWithEdit() +{ + m_xComboBox->SetTextFilter(nullptr); + m_xComboBox->SetEntryActivateHdl(Link()); + m_xComboBox->SetModifyHdl(Link()); + m_xComboBox->SetSelectHdl(Link<::ComboBox&, void>()); +} + +IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, ChangeHdl, Edit&, void) +{ + if (!m_xComboBox->IsSyntheticModify()) // SelectHdl will be called + signal_changed(); +} + +IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, SelectHdl, ::ComboBox&, void) +{ + m_bInSelect = true; + signal_changed(); + m_bInSelect = false; +} + +IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, EntryActivateHdl, Edit&, bool) +{ + return m_aEntryActivateHdl.Call(*this); +} + +IMPL_LINK(SalInstanceComboBoxWithEdit, UserDrawHdl, UserDrawEvent*, pEvent, void) +{ + call_signal_custom_render(pEvent); +} + +class SalInstanceEntryTreeView : public SalInstanceContainer, public virtual weld::EntryTreeView +{ +private: + DECL_LINK(AutocompleteHdl, Edit&, void); + DECL_LINK(KeyPressListener, VclWindowEvent&, void); + SalInstanceEntry* m_pEntry; + SalInstanceTreeView* m_pTreeView; + bool m_bTreeChange; + +public: + SalInstanceEntryTreeView(vcl::Window* pContainer, SalInstanceBuilder* pBuilder, + bool bTakeOwnership, std::unique_ptr xEntry, + std::unique_ptr xTreeView) + : EntryTreeView(std::move(xEntry), std::move(xTreeView)) + , SalInstanceContainer(pContainer, pBuilder, bTakeOwnership) + , m_pEntry(dynamic_cast(m_xEntry.get())) + , m_pTreeView(dynamic_cast(m_xTreeView.get())) + , m_bTreeChange(false) + { + assert(m_pEntry && m_pTreeView); + + Edit& rEntry = m_pEntry->getEntry(); + rEntry.SetAutocompleteHdl(LINK(this, SalInstanceEntryTreeView, AutocompleteHdl)); + rEntry.AddEventListener(LINK(this, SalInstanceEntryTreeView, KeyPressListener)); + } + + virtual void insert_separator(int /*pos*/, const OUString& /*rId*/) override { assert(false); } + + virtual void make_sorted() override + { + vcl::Window* pTreeView = m_pTreeView->getWidget(); + pTreeView->SetStyle(pTreeView->GetStyle() | WB_SORT); + } + + virtual void set_entry_completion(bool bEnable, bool /*bCaseSensitive*/) override + { + assert(!bEnable && "not implemented yet"); + (void)bEnable; + Edit& rEntry = m_pEntry->getEntry(); + rEntry.SetAutocompleteHdl(Link()); + } + + virtual void set_entry_font(const vcl::Font& rFont) override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.SetPointFont(rEntry, rFont); + rEntry.Invalidate(); + } + + virtual vcl::Font get_entry_font() override + { + Edit& rEntry = m_pEntry->getEntry(); + return rEntry.GetPointFont(rEntry); + } + + virtual void set_entry_placeholder_text(const OUString& rText) override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.SetPlaceholderText(rText); + } + + virtual void set_entry_editable(bool bEditable) override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.SetReadOnly(!bEditable); + } + + virtual void cut_entry_clipboard() override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.Cut(); + } + + virtual void copy_entry_clipboard() override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.Copy(); + } + + virtual void paste_entry_clipboard() override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.Paste(); + } + + virtual void grab_focus() override { m_xEntry->grab_focus(); } + + virtual void connect_focus_in(const Link& rLink) override + { + m_xEntry->connect_focus_in(rLink); + } + + virtual void connect_focus_out(const Link& rLink) override + { + m_xEntry->connect_focus_out(rLink); + } + + virtual bool changed_by_direct_pick() const override { return m_bTreeChange; } + + virtual void set_custom_renderer(bool /*bOn*/) override + { + assert(false && "not implemented"); + } + + virtual int get_max_mru_count() const override + { + assert(false && "not implemented"); + return 0; + } + + virtual void set_max_mru_count(int) override + { + assert(false && "not implemented"); + } + + virtual OUString get_mru_entries() const override + { + assert(false && "not implemented"); + return OUString(); + } + + virtual void set_mru_entries(const OUString&) override + { + assert(false && "not implemented"); + } + + virtual void set_item_menu(const OString&, weld::Menu*) override + { + assert(false && "not implemented"); + } + + int get_menu_button_width() const override + { + assert(false && "not implemented"); + return 0; + } + + VclPtr create_render_virtual_device() const override + { + return VclPtr::Create(); + } + + virtual ~SalInstanceEntryTreeView() override + { + Edit& rEntry = m_pEntry->getEntry(); + rEntry.RemoveEventListener(LINK(this, SalInstanceEntryTreeView, KeyPressListener)); + rEntry.SetAutocompleteHdl(Link()); + } +}; + +IMPL_LINK(SalInstanceEntryTreeView, KeyPressListener, VclWindowEvent&, rEvent, void) +{ + if (rEvent.GetId() != VclEventId::WindowKeyInput) + return; + const KeyEvent& rKeyEvent = *static_cast(rEvent.GetData()); + sal_uInt16 nKeyCode = rKeyEvent.GetKeyCode().GetCode(); + if (nKeyCode == KEY_UP || nKeyCode == KEY_DOWN || nKeyCode == KEY_PAGEUP + || nKeyCode == KEY_PAGEDOWN) + { + m_pTreeView->disable_notify_events(); + auto& rListBox = m_pTreeView->getTreeView(); + if (!rListBox.FirstSelected()) + { + if (SvTreeListEntry* pEntry = rListBox.First()) + rListBox.Select(pEntry, true); + } + else + rListBox.KeyInput(rKeyEvent); + m_xEntry->set_text(m_xTreeView->get_selected_text()); + m_xEntry->select_region(0, -1); + m_pTreeView->enable_notify_events(); + m_bTreeChange = true; + m_pEntry->fire_signal_changed(); + m_bTreeChange = false; + } +} + +IMPL_LINK(SalInstanceEntryTreeView, AutocompleteHdl, Edit&, rEdit, void) +{ + Selection aSel = rEdit.GetSelection(); + + OUString aFullText = rEdit.GetText(); + OUString aStartText = aFullText.copy(0, static_cast(aSel.Max())); + + int nPos = -1; + int nCount = m_xTreeView->n_children(); + for (int i = 0; i < nCount; ++i) + { + if (m_xTreeView->get_text(i).startsWithIgnoreAsciiCase(aStartText)) + { + nPos = i; + break; + } + } + + m_xTreeView->select(nPos); + + if (nPos != -1) + { + OUString aText = m_xTreeView->get_text(nPos); + Selection aSelection(aText.getLength(), aStartText.getLength()); + rEdit.SetText(aText, aSelection); + } +} + +SalInstanceBuilder::SalInstanceBuilder(vcl::Window* pParent, const OUString& rUIRoot, + const OUString& rUIFile) + : weld::Builder() + , m_xBuilder(new VclBuilder(pParent, rUIRoot, rUIFile, OString(), + css::uno::Reference(), false)) +{ +} + +std::unique_ptr SalInstanceBuilder::weld_message_dialog(const OString& id, + bool bTakeOwnership) +{ + MessageDialog* pMessageDialog = m_xBuilder->get(id); + std::unique_ptr pRet( + pMessageDialog ? new SalInstanceMessageDialog(pMessageDialog, this, false) : nullptr); + if (bTakeOwnership && pMessageDialog) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pMessageDialog); + m_xBuilder->drop_ownership(pMessageDialog); + } + return pRet; +} + +std::unique_ptr SalInstanceBuilder::weld_dialog(const OString& id, + bool bTakeOwnership) +{ + Dialog* pDialog = m_xBuilder->get(id); + std::unique_ptr pRet(pDialog ? new SalInstanceDialog(pDialog, this, false) + : nullptr); + if (bTakeOwnership && pDialog) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pDialog); + m_xBuilder->drop_ownership(pDialog); + } + return pRet; +} + +std::unique_ptr SalInstanceBuilder::weld_assistant(const OString& id, + bool bTakeOwnership) +{ + vcl::RoadmapWizard* pDialog = m_xBuilder->get(id); + std::unique_ptr pRet(pDialog ? new SalInstanceAssistant(pDialog, this, false) + : nullptr); + if (bTakeOwnership && pDialog) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pDialog); + m_xBuilder->drop_ownership(pDialog); + } + return pRet; +} + +std::unique_ptr SalInstanceBuilder::create_screenshot_window() +{ + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + + vcl::Window* pRoot = m_xBuilder->get_widget_root(); + if (SystemWindow* pWindow = dynamic_cast(pRoot)) + { + std::unique_ptr xRet(new SalInstanceWindow(pWindow, this, false)); + m_aOwnedToplevel.set(pWindow); + m_xBuilder->drop_ownership(pWindow); + return xRet; + } + + VclPtrInstance xDialog(nullptr, WB_HIDE | WB_STDDIALOG | WB_SIZEABLE | WB_CLOSEABLE, + Dialog::InitFlag::NoParent); + xDialog->SetText(utl::ConfigManager::getProductName()); + + auto xContentArea = VclPtr::Create(xDialog, false, 12); + pRoot->SetParent(xContentArea); + assert(pRoot == xContentArea->GetWindow(GetWindowType::FirstChild)); + xContentArea->Show(); + pRoot->Show(); + xDialog->SetHelpId(pRoot->GetHelpId()); + + m_aOwnedToplevel.set(xDialog); + + return std::unique_ptr(new SalInstanceDialog(xDialog, this, false)); +} + +std::unique_ptr SalInstanceBuilder::weld_window(const OString& id, + bool bTakeOwnership) +{ + SystemWindow* pWindow = m_xBuilder->get(id); + return pWindow ? std::make_unique(pWindow, this, bTakeOwnership) : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_widget(const OString& id, + bool bTakeOwnership) +{ + vcl::Window* pWidget = m_xBuilder->get(id); + return pWidget ? std::make_unique(pWidget, this, bTakeOwnership) : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_container(const OString& id, + bool bTakeOwnership) +{ + vcl::Window* pContainer = m_xBuilder->get(id); + return pContainer ? std::make_unique(pContainer, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_box(const OString& id, bool bTakeOwnership) +{ + vcl::Window* pContainer = m_xBuilder->get(id); + return pContainer ? std::make_unique(pContainer, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_paned(const OString& id, + bool bTakeOwnership) +{ + VclPaned* pPaned = m_xBuilder->get(id); + return pPaned ? std::make_unique(pPaned, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_frame(const OString& id, bool bTakeOwnership) +{ + VclFrame* pFrame = m_xBuilder->get(id); + std::unique_ptr pRet(pFrame ? new SalInstanceFrame(pFrame, this, false) : nullptr); + if (bTakeOwnership && pFrame) + { + assert(!m_aOwnedToplevel && "only one toplevel per .ui allowed"); + m_aOwnedToplevel.set(pFrame); + m_xBuilder->drop_ownership(pFrame); + } + return pRet; +} + +std::unique_ptr SalInstanceBuilder::weld_scrolled_window(const OString& id, + bool bTakeOwnership) +{ + VclScrolledWindow* pScrolledWindow = m_xBuilder->get(id); + return pScrolledWindow + ? std::make_unique(pScrolledWindow, this, bTakeOwnership) + : nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_notebook(const OString& id, + bool bTakeOwnership) +{ + vcl::Window* pNotebook = m_xBuilder->get(id); + if (!pNotebook) + return nullptr; + if (pNotebook->GetType() == WindowType::TABCONTROL) + return std::make_unique(static_cast(pNotebook), this, + bTakeOwnership); + if (pNotebook->GetType() == WindowType::VERTICALTABCONTROL) + return std::make_unique( + static_cast(pNotebook), this, bTakeOwnership); + return nullptr; +} + +std::unique_ptr SalInstanceBuilder::weld_button(const OString& id, + bool bTakeOwnership) +{ + Button* pButton = m_xBuilder->get