[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.1' - 8 commits - desktop/inc desktop/Library_sofficeapp.mk desktop/source include/opencl officecfg/registry opencl/inc opencl/Library_opencl.mk opencl/source Repository.mk sc/Module_sc.mk sc/Package_opencl.mk sc/source sd/source solenv/gbuild starmath/source vcl/Library_vcl.mk vcl/source

Michael Meeks michael.meeks at collabora.com
Wed Jul 13 19:15:05 UTC 2016


 Repository.mk                                                |    1 
 desktop/Library_sofficeapp.mk                                |    2 
 desktop/inc/app.hxx                                          |    1 
 desktop/source/app/app.cxx                                   |    5 
 desktop/source/app/opencl.cxx                                |  174 +++++++++++
 desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx |   14 
 include/opencl/OpenCLZone.hxx                                |   52 +++
 include/opencl/openclwrapper.hxx                             |    4 
 officecfg/registry/schema/org/openoffice/Office/Common.xcs   |    6 
 opencl/Library_opencl.mk                                     |    3 
 opencl/inc/opencl_device.hxx                                 |    3 
 opencl/inc/opencl_device_selection.h                         |    4 
 opencl/source/OpenCLZone.cxx                                 |   50 +++
 opencl/source/opencl_device.cxx                              |   23 +
 opencl/source/openclwrapper.cxx                              |  112 ++++---
 sc/Module_sc.mk                                              |    1 
 sc/Package_opencl.mk                                         |   16 +
 sc/source/core/opencl/cl-test.ods                            |binary
 sc/source/core/opencl/op_spreadsheet.cxx                     |   31 +
 sc/source/core/tool/formulagroup.cxx                         |   16 -
 sc/source/core/tool/interpr1.cxx                             |    9 
 sd/source/ui/framework/tools/FrameworkHelper.cxx             |   57 ++-
 solenv/gbuild/extensions/pre_MergedLibsList.mk               |    2 
 starmath/source/node.cxx                                     |    2 
 vcl/Library_vcl.mk                                           |    1 
 vcl/source/app/svmain.cxx                                    |    5 
 vcl/source/gdi/bitmap.cxx                                    |   36 +-
 27 files changed, 524 insertions(+), 106 deletions(-)

New commits:
commit 9252f2a95a07fff2d97f71d3b8f93ebef355abea
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Mon Jul 11 15:12:38 2016 +0100

    desktop: validate OpenCL drivers before use.
    
    OpenCL validation needs to happen before drivers are used in
    anger. This should isolate any crashes, and/or mis-behavior to
    We use app version, CL driver version and file time-stamp to
    trigger re-testing the device. If anything fails: hard disable
    OpenCL.
    
    We use an opencl validation sheet (cl-test.ods) and install it.
    It is a minimal CL set - it requires a very short formula group
    length, and combines several CL functions into few formulae to
    test more.
    
    The sheet structure, in particular the manual squaring / SQRT is
    necessary to stick within the default CL subset, and ensure that
    formulae are CL enabled from the root of the dependency tree up.
    
    Reviewed-on: https://gerrit.libreoffice.org/27131
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
    (cherry picked from commit c44726c48228d9c6a5960e302b1c0bd16b0099c4)
    
    + opencl: bail out early in missing OpenCL case.
    (cherry picked from commit 605a5dc088385ad21c33028d8107125c0316ddb1)
    
    + Remove bogus dependency from opencl to configmgr
    Since f41eb66302208f384a475fb20c98b6d1b0676cb6 "opencl: OpenCLZone, detect CL
    device change and disable CL on crash" vcl links against opencl (so indirectly
    linked against configmgr), which caused CppunitTest_configmgr_unit to include
    the configmgr object files both statically (through
    gb_CppunitTest_use_library_objects) and through the linked-in configmgr dynamic
    library, which in turn caused ASan builds to report an ODR violation for a
    doubly defined 'typeinfo name for configmgr::Access'.
    
    (cherry picked from commit 9c711f05fa10dc70e4257a1f48d43f539353541a)
    
    Reviewed-on: https://gerrit.libreoffice.org/27146
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jenkins <ci at libreoffice.org>
    (cherry picked from commit 9befbe1f81a7930e167e0a711666b0779898c12e)
    
    Change-Id: I18682dbdf9a8ba9c16d52bad4447e9acce97f0a3

diff --git a/Repository.mk b/Repository.mk
index 3554cca..8ea3dec 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -825,6 +825,7 @@ $(eval $(call gb_Helper_register_packages_for_install,ooo,\
 	) \
 	$(if $(ENABLE_OPENGL_CANVAS),canvas_opengl_shader) \
 	sfx2_classification \
+	$(if $(filter OPENCL,$(BUILD_TYPE)),sc_opencl_runtimetest) \
 ))
 
 $(eval $(call gb_Helper_register_packages_for_install,ogltrans,\
diff --git a/desktop/Library_sofficeapp.mk b/desktop/Library_sofficeapp.mk
index d2012cc..4b77bb3 100644
--- a/desktop/Library_sofficeapp.mk
+++ b/desktop/Library_sofficeapp.mk
@@ -48,6 +48,7 @@ $(eval $(call gb_Library_use_libraries,sofficeapp,\
     deploymentmisc \
     editeng \
     i18nlangtag \
+    $(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \
     sal \
     salhelper \
     sb \
@@ -95,6 +96,7 @@ $(eval $(call gb_Library_add_exception_objects,sofficeapp,\
     desktop/source/app/langselect \
     desktop/source/app/lockfile2 \
     desktop/source/app/officeipcthread \
+    desktop/source/app/opencl \
     desktop/source/app/sofficemain \
     desktop/source/app/userinstall \
     desktop/source/migration/migration \
diff --git a/desktop/inc/app.hxx b/desktop/inc/app.hxx
index d07d285..f9e7db6 100644
--- a/desktop/inc/app.hxx
+++ b/desktop/inc/app.hxx
@@ -84,6 +84,7 @@ class Desktop : public Application
 
         static void             OpenClients();
         static void             OpenDefault();
+        static void             CheckOpenCLCompute(const css::uno::Reference<css::frame::XDesktop2> &);
 
         DECL_STATIC_LINK_TYPED( Desktop, EnableAcceptors_Impl, void*, void);
 
diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx
index a46e50b..8170e03 100644
--- a/desktop/source/app/app.cxx
+++ b/desktop/source/app/app.cxx
@@ -1572,6 +1572,11 @@ int Desktop::Main()
             FatalError( MakeStartupErrorMessage(e.Message) );
         }
 
+        // FIXME: move this somewhere sensible.
+#if HAVE_FEATURE_OPENCL
+        CheckOpenCLCompute(xDesktop);
+#endif
+
         // Release solar mutex just before we wait for our client to connect
         {
             SolarMutexReleaser aReleaser;
diff --git a/desktop/source/app/opencl.cxx b/desktop/source/app/opencl.cxx
new file mode 100644
index 0000000..09f2204
--- /dev/null
+++ b/desktop/source/app/opencl.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 module exists to validate the OpenCL implementation,
+ * where necessary during startup; and before we load or
+ * calculate using OpenCL.
+ */
+
+#include "app.hxx"
+
+#include <config_version.h>
+#include <config_folders.h>
+
+#include <rtl/bootstrap.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <com/sun/star/table/XCell2.hpp>
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheets.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+
+#include <opencl/openclwrapper.hxx>
+#include <opencl/OpenCLZone.hxx>
+
+#include <osl/file.hxx>
+
+using namespace ::osl;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::frame;
+
+namespace desktop {
+
+#if HAVE_FEATURE_OPENCL
+
+bool testOpenCLCompute(const Reference< XDesktop2 > &xDesktop, const OUString &rURL)
+{
+    bool bSuccess = false;
+    css::uno::Reference< css::lang::XComponent > xComponent;
+
+    SAL_INFO("opencl", "Starting CL test spreadsheet");
+
+    try {
+        css::uno::Reference< css::frame::XComponentLoader > xLoader(xDesktop, css::uno::UNO_QUERY_THROW);
+
+        css::uno::Sequence< css::beans::PropertyValue > aArgs(1);
+        aArgs[0].Name = "Hidden";
+        aArgs[0].Value = makeAny(true);
+
+        xComponent.set(xLoader->loadComponentFromURL(rURL, "_blank", 0, aArgs));
+
+        // What an unpleasant API to use.
+        css::uno::Reference< css::sheet::XCalculatable > xCalculatable( xComponent, css::uno::UNO_QUERY_THROW);
+        css::uno::Reference< css::sheet::XSpreadsheetDocument > xSpreadDoc( xComponent, css::uno::UNO_QUERY_THROW );
+        css::uno::Reference< css::sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), css::uno::UNO_QUERY_THROW );
+        css::uno::Reference< css::container::XIndexAccess > xIndex( xSheets, css::uno::UNO_QUERY_THROW );
+        css::uno::Reference< css::sheet::XSpreadsheet > xSheet( xIndex->getByIndex(0), css::uno::UNO_QUERY_THROW);
+
+        // So we insert our MAX call at the end on a named range.
+        css::uno::Reference< css::table::XCell2 > xThresh( xSheet->getCellByPosition(1,1), css::uno::UNO_QUERY_THROW ); // B2
+        double fThreshold = xThresh->getValue();
+
+        // We need pure OCL formulae all the way through the
+        // dependency chain, or we fall-back.
+        xCalculatable->calculateAll();
+
+        // So we insert our MAX call at the end on a named range.
+        css::uno::Reference< css::table::XCell2 > xCell( xSheet->getCellByPosition(1,0), css::uno::UNO_QUERY_THROW );
+        xCell->setFormula("=MAX(results)");
+        double fResult = xCell->getValue();
+
+        // Ensure the maximum variance is below our tolerance.
+        if (fResult > fThreshold)
+        {
+            SAL_WARN("opencl", "OpenCL results unstable - disabling; result: "
+                     << fResult << " vs. " << fThreshold);
+        }
+        else
+        {
+            SAL_INFO("opencl", "calculating smoothly; result: " << fResult);
+            bSuccess = true;
+        }
+    }
+    catch (const css::uno::Exception &e)
+    {
+        (void)e;
+        SAL_WARN("opencl", "OpenCL testing failed - disabling: " << e.Message);
+    }
+
+    if (!bSuccess)
+        OpenCLZone::hardDisable();
+    if (xComponent.is())
+        xComponent->dispose();
+
+    return bSuccess;
+}
+
+void Desktop::CheckOpenCLCompute(const Reference< XDesktop2 > &xDesktop)
+{
+    if (getenv("SAL_DISABLE_OPENCL") ||
+        !officecfg::Office::Common::Misc::UseOpenCL::get())
+        return;
+
+    SAL_INFO("opencl", "Initiating test of OpenCL device");
+    OpenCLZone aZone;
+
+    OUString aDevice = officecfg::Office::Calc::Formula::Calculation::OpenCLDevice::get();
+    OUString aSelectedCLDeviceVersionID;
+    if (!opencl::switchOpenCLDevice(
+            &aDevice,
+            officecfg::Office::Calc::Formula::Calculation::OpenCLAutoSelect::get(),
+            false /* bForceEvaluation */,
+            aSelectedCLDeviceVersionID))
+    {
+        SAL_WARN("opencl", "Failed to initialize OpenCL for test");
+        OpenCLZone::hardDisable();
+        return;
+    }
+
+    // Append our app version as well.
+    aSelectedCLDeviceVersionID += "--";
+    aSelectedCLDeviceVersionID += LIBO_VERSION_DOTTED;
+
+    // Append timestamp of the file.
+    OUString aURL("$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/opencl/cl-test.ods");
+    rtl::Bootstrap::expandMacros(aURL);
+
+    DirectoryItem aItem;
+    DirectoryItem::get( aURL, aItem );
+    FileStatus aFileStatus( osl_FileStatus_Mask_ModifyTime );
+    aItem.getFileStatus( aFileStatus );
+    TimeValue aTimeVal = aFileStatus.getModifyTime();
+    aSelectedCLDeviceVersionID += "--";
+    aSelectedCLDeviceVersionID += OUString::number(aTimeVal.Seconds);
+
+    if (aSelectedCLDeviceVersionID != officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::get())
+    {
+        // OpenCL device changed - sanity check it and disable if bad.
+
+        boost::optional<sal_Int32> nOrigMinimumSize = officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::get();
+        { // set the group size to something small for quick testing.
+            std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+            officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(3 /* small */, xBatch);
+            xBatch->commit();
+        }
+
+        bool bSucceeded = testOpenCLCompute(xDesktop, aURL);
+
+        // it passed -> save the device.
+        {
+            std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+            officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(nOrigMinimumSize, xBatch);
+            // allow the user to subsequently manually enable it.
+            officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::set(aSelectedCLDeviceVersionID, xBatch);
+            xBatch->commit();
+        }
+
+        if (!bSucceeded)
+            OpenCLZone::hardDisable();
+    }
+}
+#endif // HAVE_FEATURE_OPENCL
+
+} // end namespace desktop
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/opencl/Library_opencl.mk b/opencl/Library_opencl.mk
index 3d9b032..927de0f 100644
--- a/opencl/Library_opencl.mk
+++ b/opencl/Library_opencl.mk
@@ -34,7 +34,6 @@ $(eval $(call gb_Library_use_sdk_api,opencl))
 
 $(eval $(call gb_Library_use_libraries,opencl,\
     clew \
-    configmgr \
     comphelper \
     cppu \
     sal \
diff --git a/opencl/inc/opencl_device.hxx b/opencl/inc/opencl_device.hxx
index 0963304..216af72 100644
--- a/opencl/inc/opencl_device.hxx
+++ b/opencl/inc/opencl_device.hxx
@@ -16,6 +16,9 @@ namespace opencl {
 
 ds_device getDeviceSelection(OUString const & pFileName, bool bForceSelection = false);
 
+struct GPUEnv;
+void releaseOpenCLEnv( GPUEnv *gpuInfo );
+
 }
 
 #endif
diff --git a/opencl/source/OpenCLZone.cxx b/opencl/source/OpenCLZone.cxx
index dc3a952..03521a2 100644
--- a/opencl/source/OpenCLZone.cxx
+++ b/opencl/source/OpenCLZone.cxx
@@ -7,7 +7,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include <opencl/openclwrapper.hxx>
 #include <opencl/OpenCLZone.hxx>
+#include "opencl_device.hxx"
 
 #include <memory>
 
@@ -40,6 +42,8 @@ void OpenCLZone::hardDisable()
         auto xConfProvider = css::configuration::theDefaultProvider::get(comphelper::getProcessComponentContext());
         css::uno::Reference<css::util::XFlushable> xFlushable(xConfProvider, css::uno::UNO_QUERY_THROW);
         xFlushable->flush();
+
+        releaseOpenCLEnv(&opencl::gpuEnv);
     }
 }
 
diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx
index 1af142c..807a185 100644
--- a/opencl/source/openclwrapper.cxx
+++ b/opencl/source/openclwrapper.cxx
@@ -269,6 +269,8 @@ bool initOpenCLAttr( OpenCLEnv * env )
     return false;
 }
 
+}
+
 void releaseOpenCLEnv( GPUEnv *gpuInfo )
 {
     OpenCLZone zone;
@@ -299,6 +301,8 @@ void releaseOpenCLEnv( GPUEnv *gpuInfo )
     return;
 }
 
+namespace {
+
 bool buildProgram(const char* buildOption, GPUEnv* gpuInfo, int idx)
 {
     cl_int clStatus;
@@ -696,7 +700,7 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_
 
 bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation, OUString& rOutSelectedDeviceVersionIDString)
 {
-    if(fillOpenCLInfo().empty())
+    if(fillOpenCLInfo().empty() || getenv("SAL_DISABLE_OPENCL"))
         return false;
 
     cl_device_id pDeviceId = nullptr;
diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk
index d656f71..e135e30 100644
--- a/sc/Module_sc.mk
+++ b/sc/Module_sc.mk
@@ -15,6 +15,7 @@ $(eval $(call gb_Module_add_targets,sc,\
 	Library_scd \
 	Library_scfilt \
 	$(call gb_Helper_optional,DESKTOP,Library_scui) \
+	$(call gb_Helper_optional,OPENCL,Package_opencl) \
 ))
 
 $(eval $(call gb_Module_add_l10n_targets,sc,\
diff --git a/sc/Package_opencl.mk b/sc/Package_opencl.mk
new file mode 100644
index 0000000..ef1579f
--- /dev/null
+++ b/sc/Package_opencl.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,sc_opencl_runtimetest,$(SRCDIR)/sc/source/core/opencl))
+
+$(eval $(call gb_Package_add_files,sc_opencl_runtimetest,$(LIBO_ETC_FOLDER)/opencl,\
+	cl-test.ods \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sc/source/core/opencl/cl-test.ods b/sc/source/core/opencl/cl-test.ods
new file mode 100644
index 0000000..8380e0b
Binary files /dev/null and b/sc/source/core/opencl/cl-test.ods differ
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index abe92e8..8f166ce 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -338,26 +338,9 @@ bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool
         return false;
 
     delete msInstance;
-    msInstance = nullptr;
+    msInstance = new sc::opencl::FormulaGroupInterpreterOpenCL();
 
-    if (bOpenCLEnabled)
-    {
-        msInstance = new sc::opencl::FormulaGroupInterpreterOpenCL();
-
-        if (aSelectedCLDeviceVersionID != officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::get())
-        {
-            // perform OpenCL calculation tests
-
-            // save the device
-            std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
-            officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::set(aSelectedCLDeviceVersionID, xBatch);
-            xBatch->commit();
-        }
-
-        return msInstance != nullptr;
-    }
-
-    return false;
+    return true;
 }
 
 void FormulaGroupInterpreter::getOpenCLDeviceInfo(sal_Int32& rDeviceId, sal_Int32& rPlatformId)
diff --git a/solenv/gbuild/extensions/pre_MergedLibsList.mk b/solenv/gbuild/extensions/pre_MergedLibsList.mk
index b338570..20cc510 100644
--- a/solenv/gbuild/extensions/pre_MergedLibsList.mk
+++ b/solenv/gbuild/extensions/pre_MergedLibsList.mk
@@ -12,6 +12,7 @@
 MERGE_LIBRARY_LIST := \
 	avmedia \
 	$(if $(filter $(OS),ANDROID),,basebmp) \
+	$(if $(filter OPENCL,$(BUILD_TYPE)),clew) \
 	basegfx \
 	canvastools \
 	configmgr \
commit e79f63ee76b2c4dd2e47c250e07931433305855c
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Jul 8 22:16:27 2016 +0900

    opencl: OpenCLZone, detect CL device change and disable CL on crash
    
    Guard OpenCL calls with OpenCLZone, so if a OpenCL call crashes we
    detect this and disable OpenCL so next time the user doesn't encounter
    the crash at the same calculation because he has a broken OpenCL
    drivers. Similar has been implemented for OpenGL with good results.
    
    Additionaly we persistently remember a known good OpenCL device ID and
    driver version so we can match this and perform calculation tests when
    they change. This is to ensure that the selected OpenCL device performs
    as we expect. In this commit the calculation tests aren't included yet.
    
    Remove complex static initializer in opencl wrapper library.
    
    Reviewed-on: https://gerrit.libreoffice.org/27064
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>
    (cherry picked from commit f41eb66302208f384a475fb20c98b6d1b0676cb6)
    
    Change-Id: I1a8b81ee31298731efcf63dc6a476955afc035e9
    Reviewed-on: https://gerrit.libreoffice.org/27103
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
    (cherry picked from commit e1ef22371613f384cc2f6fc75d022cb01bf92af7)

diff --git a/include/opencl/OpenCLZone.hxx b/include/opencl/OpenCLZone.hxx
new file mode 100644
index 0000000..1fbc666
--- /dev/null
+++ b/include/opencl/OpenCLZone.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/.
+ */
+
+#ifndef INCLUDED_OPENCL_INC_OPENCL_ZONE_HXX
+#define INCLUDED_OPENCL_INC_OPENCL_ZONE_HXX
+
+#include <opencl/opencldllapi.h>
+
+// FIXME: post back-port, templatize me and share with OpenGLZone.
+class OPENCL_DLLPUBLIC OpenCLZone
+{
+    /// how many times have we entered a CL zone
+    static volatile sal_uInt64 gnEnterCount;
+    /// how many times have we left a new CL zone
+    static volatile sal_uInt64 gnLeaveCount;
+
+    static void enter()
+    {
+        gnEnterCount++;
+    }
+    static void leave()
+    {
+        gnLeaveCount--;
+    }
+public:
+    OpenCLZone()
+    {
+        gnEnterCount++;
+    }
+
+    ~OpenCLZone()
+    {
+        gnLeaveCount++;
+    }
+
+    static bool isInZone()
+    {
+        return gnEnterCount != gnLeaveCount;
+    }
+
+    static void hardDisable();
+};
+
+#endif // INCLUDED_OPENCL_INC_OPENCL_ZONE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/opencl/openclwrapper.hxx b/include/opencl/openclwrapper.hxx
index 5205aaa..2121f0e 100644
--- a/include/opencl/openclwrapper.hxx
+++ b/include/opencl/openclwrapper.hxx
@@ -66,11 +66,13 @@ OPENCL_DLLPUBLIC const std::vector<OpenCLPlatformInfo>& fillOpenCLInfo();
  *
  * @param pDeviceId the id of the opencl device of type cl_device_id, NULL means use software calculation
  * @param bAutoSelect use the algorithm to select the best OpenCL device
+ * @param rOutSelectedDeviceVersionIDString returns the selected device's version string.
  *
  * @return returns true if there is a valid opencl device that has been set up
  */
 OPENCL_DLLPUBLIC bool switchOpenCLDevice(const OUString* pDeviceId, bool bAutoSelect,
-                                         bool bForceEvaluation);
+                                         bool bForceEvaluation,
+                                         OUString& rOutSelectedDeviceVersionIDString);
 
 OPENCL_DLLPUBLIC void getOpenCLDeviceInfo(size_t& rDeviceId, size_t& rPlatformId);
 
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index f6d717e..415eec3 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -5647,6 +5647,12 @@
         </info>
         <value oor:separator=";">Linux//Advanced Micro Devices, Inc\.//1445\.5 \(sse2,avx\);//Advanced Micro Devices, Inc\.//;//Intel\(R\) Corporation//;//NVIDIA Corporation//</value>
       </prop>
+      <prop oor:name="SelectedOpenCLDeviceIdentifier" oor:type="xs:string" oor:nillable="false">
+        <info>
+          <desc>The OpenCL device identifier of a device that was successfully selected and passed the OpenCL calculation tests.</desc>
+        </info>
+        <value>none</value>
+      </prop>
       <prop oor:name="UseSwInterpreter" oor:type="xs:boolean" oor:nillable="false">
         <info>
           <desc>Determines whether Software Interpreter can be used to speed
diff --git a/opencl/Library_opencl.mk b/opencl/Library_opencl.mk
index 4529da7..3d9b032 100644
--- a/opencl/Library_opencl.mk
+++ b/opencl/Library_opencl.mk
@@ -38,6 +38,7 @@ $(eval $(call gb_Library_use_libraries,opencl,\
     comphelper \
     cppu \
     sal \
+    salhelper \
     tl \
 ))
 
@@ -46,6 +47,7 @@ $(eval $(call gb_Library_add_exception_objects,opencl,\
     opencl/source/openclwrapper \
     opencl/source/opencl_device \
     opencl/source/platforminfo \
+    opencl/source/OpenCLZone \
 ))
 
 ifeq ($(OS),LINUX)
diff --git a/opencl/inc/opencl_device_selection.h b/opencl/inc/opencl_device_selection.h
index e2bda73..7d46f29 100644
--- a/opencl/inc/opencl_device_selection.h
+++ b/opencl/inc/opencl_device_selection.h
@@ -24,6 +24,8 @@
 #include <tools/stream.hxx>
 #include <rtl/math.hxx>
 
+#include <opencl/OpenCLZone.hxx>
+
 #include <vector>
 
 enum ds_status
@@ -127,6 +129,8 @@ inline bool getDeviceInfoBool(cl_device_id aDeviceId, cl_device_info aDeviceInfo
 
 inline ds_status initDSProfile(std::unique_ptr<ds_profile>& rProfile, OString rVersion)
 {
+    OpenCLZone zone;
+
     int numDevices;
     cl_uint numPlatforms;
     std::vector<cl_platform_id> platforms;
diff --git a/opencl/source/OpenCLZone.cxx b/opencl/source/OpenCLZone.cxx
new file mode 100644
index 0000000..dc3a952
--- /dev/null
+++ b/opencl/source/OpenCLZone.cxx
@@ -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/.
+ */
+
+#include <opencl/OpenCLZone.hxx>
+
+#include <memory>
+
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <com/sun/star/configuration/theDefaultProvider.hpp>
+
+// FIXME: templatize me vs. OpenGLZone.
+
+sal_uInt64 volatile OpenCLZone::gnEnterCount = 0;
+sal_uInt64 volatile OpenCLZone::gnLeaveCount = 0;
+
+/**
+ * Called from a signal handler if we get
+ * a crash or hang in some CL code.
+ */
+void OpenCLZone::hardDisable()
+{
+    // protect ourselves from double calling etc.
+    static bool bDisabled = false;
+    if (!bDisabled)
+    {
+        bDisabled = true;
+
+        std::shared_ptr<comphelper::ConfigurationChanges> xChanges(comphelper::ConfigurationChanges::create());
+        officecfg::Office::Common::Misc::UseOpenCL::set(false, xChanges);
+        xChanges->commit();
+
+        // Force synchronous config write
+        auto xConfProvider = css::configuration::theDefaultProvider::get(comphelper::getProcessComponentContext());
+        css::uno::Reference<css::util::XFlushable> xFlushable(xConfProvider, css::uno::UNO_QUERY_THROW);
+        xFlushable->flush();
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/opencl/source/opencl_device.cxx b/opencl/source/opencl_device.cxx
index 85fea92..d87ead8 100644
--- a/opencl/source/opencl_device.cxx
+++ b/opencl/source/opencl_device.cxx
@@ -30,6 +30,8 @@
 #include <opencl/platforminfo.hxx>
 #include <sal/log.hxx>
 
+#include <opencl/OpenCLZone.hxx>
+
 #include "opencl_device.hxx"
 
 #define INPUTSIZE  15360
@@ -200,14 +202,21 @@ ds_status evaluateScoreForDevice(ds_device& rDevice, std::unique_ptr<LibreOffice
         /* Evaluating an OpenCL device */
         SAL_INFO("opencl.device", "Device: \"" << rDevice.sDeviceName << "\" (OpenCL) evaluation...");
         cl_int clStatus;
+
         /* Check for 64-bit float extensions */
-        size_t aDevExtInfoSize = 0;
-        clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize);
-        DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
+        std::unique_ptr<char[]> aExtInfo;
+        {
+            size_t aDevExtInfoSize = 0;
+
+            OpenCLZone zone;
+            clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize);
+            DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
+
+            aExtInfo.reset(new char[aDevExtInfoSize]);
+            clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr);
+            DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
+        }
 
-        std::unique_ptr<char[]> aExtInfo(new char[aDevExtInfoSize]);
-        clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr);
-        DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
         bool bKhrFp64Flag = false;
         bool bAmdFp64Flag = false;
         const char* buildOption = nullptr;
@@ -244,6 +253,8 @@ ds_status evaluateScoreForDevice(ds_device& rDevice, std::unique_ptr<LibreOffice
         {
             /* 64-bit float support present */
 
+            OpenCLZone zone;
+
             /* Create context and command queue */
             cl_context  clContext = clCreateContext(nullptr, 1, &rDevice.aDeviceID, nullptr, nullptr, &clStatus);
             DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateContext");
diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx
index 384e9eb..1af142c 100644
--- a/opencl/source/openclwrapper.cxx
+++ b/opencl/source/openclwrapper.cxx
@@ -21,6 +21,7 @@
 #include <rtl/ustring.hxx>
 #include <sal/config.h>
 #include <sal/log.hxx>
+#include <opencl/OpenCLZone.hxx>
 
 #include <memory>
 #include <unicode/regex.h>
@@ -82,15 +83,19 @@ OString generateMD5(const void* pData, size_t length)
 
 OString getCacheFolder()
 {
-    OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
-    rtl::Bootstrap::expandMacros(url);
+    static OString aCacheFolder;
 
-    osl::Directory::create(url);
+    if (aCacheFolder.isEmpty())
+    {
+        OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
+        rtl::Bootstrap::expandMacros(url);
 
-    return rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8);
-}
+        osl::Directory::create(url);
 
-OString maCacheFolder = getCacheFolder();
+        aCacheFolder = rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8);
+    }
+    return aCacheFolder;
+}
 
 }
 
@@ -132,8 +137,7 @@ OString createFileName(cl_device_id deviceId, const char* clFileName)
     OString aString = OString(deviceName) + driverVersion + platformVersion;
     OString aHash = generateMD5(aString.getStr(), aString.getLength());
 
-    return maCacheFolder + fileName + "-" +
-        aHash + ".bin";
+    return getCacheFolder() + fileName + "-" + aHash + ".bin";
 }
 
 std::vector<std::shared_ptr<osl::File> > binaryGenerated( const char * clFileName, cl_context context )
@@ -267,6 +271,8 @@ bool initOpenCLAttr( OpenCLEnv * env )
 
 void releaseOpenCLEnv( GPUEnv *gpuInfo )
 {
+    OpenCLZone zone;
+
     if ( !bIsInited )
     {
         return;
@@ -319,7 +325,7 @@ bool buildProgram(const char* buildOption, GPUEnv* gpuInfo, int idx)
             return false;
         }
 
-        OString aBuildLogFileURL = maCacheFolder + "kernel-build.log";
+        OString aBuildLogFileURL = getCacheFolder() + "kernel-build.log";
         osl::File aBuildLogFile(rtl::OStringToOUString(aBuildLogFileURL, RTL_TEXTENCODING_UTF8));
         osl::FileBase::RC status = aBuildLogFile.open(
                 osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
@@ -410,6 +416,8 @@ namespace {
 
 void checkDeviceForDoubleSupport(cl_device_id deviceId, bool& bKhrFp64, bool& bAmdFp64)
 {
+    OpenCLZone zone;
+
     bKhrFp64 = false;
     bAmdFp64 = false;
 
@@ -442,6 +450,8 @@ void checkDeviceForDoubleSupport(cl_device_id deviceId, bool& bKhrFp64, bool& bA
 
 bool initOpenCLRunEnv( GPUEnv *gpuInfo )
 {
+    OpenCLZone zone;
+
     bool bKhrFp64 = false;
     bool bAmdFp64 = false;
 
@@ -684,7 +694,7 @@ void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_
 
 }
 
-bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation)
+bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation, OUString& rOutSelectedDeviceVersionIDString)
 {
     if(fillOpenCLInfo().empty())
         return false;
@@ -716,54 +726,62 @@ bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEv
         return pDeviceId != nullptr;
     }
 
+    cl_context context;
     cl_platform_id platformId;
-    cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM,
-            sizeof(platformId), &platformId, nullptr);
-
-    cl_context_properties cps[3];
-    cps[0] = CL_CONTEXT_PLATFORM;
-    cps[1] = reinterpret_cast<cl_context_properties>(platformId);
-    cps[2] = 0;
-    cl_context context = clCreateContext( cps, 1, &pDeviceId, nullptr, nullptr, &nState );
-    if (nState != CL_SUCCESS)
-        SAL_WARN("opencl", "clCreateContext failed: " << errorString(nState));
+    cl_command_queue command_queue[OPENCL_CMDQUEUE_SIZE];
 
-    if(nState != CL_SUCCESS || context == nullptr)
     {
-        if(context != nullptr)
-            clReleaseContext(context);
+        OpenCLZone zone;
+        cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM,
+                                        sizeof(platformId), &platformId, nullptr);
+
+        cl_context_properties cps[3];
+        cps[0] = CL_CONTEXT_PLATFORM;
+        cps[1] = reinterpret_cast<cl_context_properties>(platformId);
+        cps[2] = 0;
+        context = clCreateContext( cps, 1, &pDeviceId, nullptr, nullptr, &nState );
+        if (nState != CL_SUCCESS)
+            SAL_WARN("opencl", "clCreateContext failed: " << errorString(nState));
 
-        SAL_WARN("opencl", "failed to set/switch opencl device");
-        return false;
-    }
-    SAL_INFO("opencl", "Created context " << context << " for platform " << platformId << ", device " << pDeviceId);
+        if(nState != CL_SUCCESS || context == nullptr)
+        {
+            if(context != nullptr)
+                clReleaseContext(context);
 
-    cl_command_queue command_queue[OPENCL_CMDQUEUE_SIZE];
-    for (int i = 0; i < OPENCL_CMDQUEUE_SIZE; ++i)
-    {
-        command_queue[i] = clCreateCommandQueue(
-            context, pDeviceId, 0, &nState);
-        if (nState != CL_SUCCESS)
-            SAL_WARN("opencl", "clCreateCommandQueue failed: " << errorString(nState));
+            SAL_WARN("opencl", "failed to set/switch opencl device");
+            return false;
+        }
+        SAL_INFO("opencl", "Created context " << context << " for platform " << platformId << ", device " << pDeviceId);
 
-        if (command_queue[i] == nullptr || nState != CL_SUCCESS)
+        for (int i = 0; i < OPENCL_CMDQUEUE_SIZE; ++i)
         {
-            // Release all command queues created so far.
-            for (int j = 0; j <= i; ++j)
+            command_queue[i] = clCreateCommandQueue(
+                context, pDeviceId, 0, &nState);
+            if (nState != CL_SUCCESS)
+                SAL_WARN("opencl", "clCreateCommandQueue failed: " << errorString(nState));
+
+            if (command_queue[i] == nullptr || nState != CL_SUCCESS)
             {
-                if (command_queue[j])
+                // Release all command queues created so far.
+                for (int j = 0; j <= i; ++j)
                 {
-                    clReleaseCommandQueue(command_queue[j]);
-                    command_queue[j] = nullptr;
+                    if (command_queue[j])
+                    {
+                        clReleaseCommandQueue(command_queue[j]);
+                        command_queue[j] = nullptr;
+                    }
                 }
+
+                clReleaseContext(context);
+                SAL_WARN("opencl", "failed to set/switch opencl device");
+                return false;
             }
 
-            clReleaseContext(context);
-            SAL_WARN("opencl", "failed to set/switch opencl device");
-            return false;
+            SAL_INFO("opencl", "Created command queue " << command_queue[i] << " for context " << context);
         }
 
-        SAL_INFO("opencl", "Created command queue " << command_queue[i] << " for context " << context);
+        OString sDeviceID = getDeviceInfoString(pDeviceId, CL_DEVICE_VENDOR) + " " + getDeviceInfoString(pDeviceId, CL_DRIVER_VERSION);
+        rOutSelectedDeviceVersionIDString = OStringToOUString(sDeviceID, RTL_TEXTENCODING_UTF8);
     }
 
     setOpenCLCmdQueuePosition(0); // Call this just to avoid the method being deleted from unused function deleter.
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index f2f8acf..abe92e8 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -32,7 +32,7 @@
 #include <vector>
 
 #if HAVE_FEATURE_OPENCL
-#include <opencl/openclwrapper.hxx>
+#  include <opencl/openclwrapper.hxx>
 #endif
 
 namespace sc {
@@ -331,7 +331,9 @@ bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool
 
         return false;
     }
-    bool bSuccess = ::opencl::switchOpenCLDevice(&rDeviceId, bAutoSelect, bForceEvaluation);
+
+    OUString aSelectedCLDeviceVersionID;
+    bool bSuccess = ::opencl::switchOpenCLDevice(&rDeviceId, bAutoSelect, bForceEvaluation, aSelectedCLDeviceVersionID);
     if(!bSuccess)
         return false;
 
@@ -341,6 +343,17 @@ bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool
     if (bOpenCLEnabled)
     {
         msInstance = new sc::opencl::FormulaGroupInterpreterOpenCL();
+
+        if (aSelectedCLDeviceVersionID != officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::get())
+        {
+            // perform OpenCL calculation tests
+
+            // save the device
+            std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+            officecfg::Office::Common::Misc::SelectedOpenCLDeviceIdentifier::set(aSelectedCLDeviceVersionID, xBatch);
+            xBatch->commit();
+        }
+
         return msInstance != nullptr;
     }
 
diff --git a/solenv/gbuild/extensions/pre_MergedLibsList.mk b/solenv/gbuild/extensions/pre_MergedLibsList.mk
index 97953ee..b338570 100644
--- a/solenv/gbuild/extensions/pre_MergedLibsList.mk
+++ b/solenv/gbuild/extensions/pre_MergedLibsList.mk
@@ -35,6 +35,7 @@ MERGE_LIBRARY_LIST := \
 	localebe1 \
 	mcnttype \
 	msfilter \
+	$(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \
 	package2 \
 	sax \
 	sb \
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 7b9ad01..346532f 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -85,6 +85,7 @@ $(eval $(call gb_Library_use_libraries,vcl,\
     cppuhelper \
     i18nlangtag \
     i18nutil \
+    $(if $(filter OPENCL,$(BUILD_TYPE)),opencl) \
     cppu \
     sal \
     salhelper \
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
index e6f4be1..0de16d9 100644
--- a/vcl/source/app/svmain.cxx
+++ b/vcl/source/app/svmain.cxx
@@ -82,6 +82,7 @@
 #include <cppuhelper/implbase.hxx>
 #include "uno/current_context.hxx"
 
+#include <opencl/OpenCLZone.hxx>
 #include "opengl/zone.hxx"
 #include "opengl/watchdog.hxx"
 
@@ -112,6 +113,10 @@ oslSignalAction SAL_CALL VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo
             nVCLException = EXC_SYSTEM;
             if (OpenGLZone::isInZone())
                 OpenGLZone::hardDisable();
+#if HAVE_FEATURE_OPENCL
+            if (OpenCLZone::isInZone())
+                OpenCLZone::hardDisable();
+#endif
         }
 
         // RC
commit c44abe5735f17dcb678748766bf40ccf035642fd
Author: David Tardon <dtardon at redhat.com>
Date:   Mon Jul 11 11:59:41 2016 +0200

    rhbz#1351292 correctly set edit mode
    
    ... when switching between different shells, e.g., from Outline to Slide
    master.
    
    Change-Id: I22ef6f6cac73c52fb1bedd97e653b4b57c5a7a24
    (cherry picked from commit b0535f3944975c1f6cdadc149d70502843331f86)
    Reviewed-on: https://gerrit.libreoffice.org/27110
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 570ad81bcbc56b1d20378c6342c27458fcee430c)

diff --git a/sd/source/ui/framework/tools/FrameworkHelper.cxx b/sd/source/ui/framework/tools/FrameworkHelper.cxx
index 842df16..ed74b7e 100644
--- a/sd/source/ui/framework/tools/FrameworkHelper.cxx
+++ b/sd/source/ui/framework/tools/FrameworkHelper.cxx
@@ -518,6 +518,41 @@ OUString FrameworkHelper::GetViewURL (ViewShell::ShellType eType)
     }
 }
 
+namespace
+{
+
+void updateEditMode(const Reference<XView> &xView, FrameworkHelper* const pHelper, const EditMode eEMode, bool updateFrameView)
+{
+    // Ensure we have the expected edit mode
+    // The check is only for DrawViewShell as OutlineViewShell
+    // and SlideSorterViewShell have no master mode
+    const ::std::shared_ptr<ViewShell> pCenterViewShell (pHelper->GetViewShell(xView));
+    DrawViewShell* pDrawViewShell
+        = dynamic_cast<DrawViewShell*>(pCenterViewShell.get());
+    if (pDrawViewShell != nullptr)
+    {
+        pCenterViewShell->Broadcast (
+            ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
+
+        pDrawViewShell->ChangeEditMode(eEMode, pDrawViewShell->IsLayerModeActive());
+        if (updateFrameView)
+            pDrawViewShell->WriteFrameViewData();
+
+        pCenterViewShell->Broadcast (
+            ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+    }
+}
+
+void asyncUpdateEditMode(FrameworkHelper* const pHelper, const EditMode eEMode)
+{
+    Reference<XResourceId> xPaneId (
+        FrameworkHelper::CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
+    Reference<XView> xView (pHelper->GetView(xPaneId));
+    updateEditMode(xView, pHelper, eEMode, true);
+}
+
+}
+
 void FrameworkHelper::HandleModeChangeSlot (
     sal_uLong nSlotId,
     SfxRequest& rRequest)
@@ -552,7 +587,6 @@ void FrameworkHelper::HandleModeChangeSlot (
         Reference<XResourceId> xPaneId (
             CreateResourceId(framework::FrameworkHelper::msCenterPaneURL));
         Reference<XView> xView (GetView(xPaneId));
-        ::std::shared_ptr<ViewShell> pCenterViewShell (GetViewShell(xView));
 
         // Compute requested view
         OUString sRequestedView;
@@ -595,26 +629,15 @@ void FrameworkHelper::HandleModeChangeSlot (
         if (!(xView.is() && xView->getResourceId()->getResourceURL().equals(sRequestedView)))
 
         {
+            const auto xId = CreateResourceId(sRequestedView, msCenterPaneURL);
             mxConfigurationController->requestResourceActivation(
-                CreateResourceId(sRequestedView, msCenterPaneURL),
+                xId,
                 ResourceActivationMode_REPLACE);
+            RunOnResourceActivation(xId, std::bind(&asyncUpdateEditMode, this, eEMode));
         }
-
-        // Ensure we have the expected edit mode
-        // The check is only for DrawViewShell as OutlineViewShell
-        // and SlideSorterViewShell have no master mode
-        DrawViewShell* pDrawViewShell
-            = dynamic_cast<DrawViewShell*>(pCenterViewShell.get());
-        if (pDrawViewShell != nullptr)
+        else
         {
-            pCenterViewShell->Broadcast (
-                ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START));
-
-            pDrawViewShell->ChangeEditMode (
-                eEMode, pDrawViewShell->IsLayerModeActive());
-
-            pCenterViewShell->Broadcast (
-                ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END));
+            updateEditMode(xView, this, eEMode, false);
         }
     }
     catch (RuntimeException&)
commit daec172029c55d2418990e1e90fdcf24f25cb4f3
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Mon Jul 11 10:13:16 2016 +0100

    Resolves: tdf#100463 tolerence in contour editor doesn't work
    
    probably since
    
    commit f51f03a46102333bac6a7fe06bc8538492f413a5
    Author: Stephan Bergmann <sbergman at redhat.com>
    Date:   Wed Mar 5 12:24:14 2014 +0100
    
        Do not needlessly truncate MinMax argument before comparison with bounds
    
    Change-Id: I5c92f0af3e05ad68ed88fa860b36e8426e160bf9
    (cherry picked from commit d5bd18ecac5806b7b4e39a1919b6b56df0f94ce3)
    Reviewed-on: https://gerrit.libreoffice.org/27102
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 95024423f38a5050f614e2d14837eebdbc348a4a)

diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx
index 6b675ed..6141e1b 100644
--- a/vcl/source/gdi/bitmap.cxx
+++ b/vcl/source/gdi/bitmap.cxx
@@ -1257,12 +1257,12 @@ Bitmap Bitmap::CreateMask( const Color& rTransColor, sal_uLong nTol ) const
             {
                 BitmapColor aCol;
                 long        nR, nG, nB;
-                const long  nMinR = MinMax( (long) rTransColor.GetRed() - nTol, 0, 255 );
-                const long  nMaxR = MinMax( (long) rTransColor.GetRed() + nTol, 0, 255 );
-                const long  nMinG = MinMax( (long) rTransColor.GetGreen() - nTol, 0, 255 );
-                const long  nMaxG = MinMax( (long) rTransColor.GetGreen() + nTol, 0, 255 );
-                const long  nMinB = MinMax( (long) rTransColor.GetBlue() - nTol, 0, 255 );
-                const long  nMaxB = MinMax( (long) rTransColor.GetBlue() + nTol, 0, 255 );
+                const long  nMinR = MinMax<long>(rTransColor.GetRed() - nTol, 0, 255);
+                const long  nMaxR = MinMax<long>(rTransColor.GetRed() + nTol, 0, 255);
+                const long  nMinG = MinMax<long>(rTransColor.GetGreen() - nTol, 0, 255);
+                const long  nMaxG = MinMax<long>(rTransColor.GetGreen() + nTol, 0, 255);
+                const long  nMinB = MinMax<long>(rTransColor.GetBlue() - nTol, 0, 255);
+                const long  nMaxB = MinMax<long>(rTransColor.GetBlue() + nTol, 0, 255);
 
                 if( pReadAcc->HasPalette() )
                 {
@@ -1579,12 +1579,12 @@ bool Bitmap::Replace( const Color& rSearchColor, const Color& rReplaceColor, sal
 
     if( pAcc )
     {
-        const long  nMinR = MinMax( (long) rSearchColor.GetRed() - nTol, 0, 255 );
-        const long  nMaxR = MinMax( (long) rSearchColor.GetRed() + nTol, 0, 255 );
-        const long  nMinG = MinMax( (long) rSearchColor.GetGreen() - nTol, 0, 255 );
-        const long  nMaxG = MinMax( (long) rSearchColor.GetGreen() + nTol, 0, 255 );
-        const long  nMinB = MinMax( (long) rSearchColor.GetBlue() - nTol, 0, 255 );
-        const long  nMaxB = MinMax( (long) rSearchColor.GetBlue() + nTol, 0, 255 );
+        const long  nMinR = MinMax<long>(rSearchColor.GetRed() - nTol, 0, 255);
+        const long  nMaxR = MinMax<long>(rSearchColor.GetRed() + nTol, 0, 255);
+        const long  nMinG = MinMax<long>(rSearchColor.GetGreen() - nTol, 0, 255);
+        const long  nMaxG = MinMax<long>(rSearchColor.GetGreen() + nTol, 0, 255);
+        const long  nMinB = MinMax<long>(rSearchColor.GetBlue() - nTol, 0, 255);
+        const long  nMaxB = MinMax<long>(rSearchColor.GetBlue() + nTol, 0, 255);
 
         if( pAcc->HasPalette() )
         {
@@ -1663,12 +1663,12 @@ bool Bitmap::Replace( const Color* pSearchColors, const Color* pReplaceColors,
             const Color&    rCol = pSearchColors[ i ];
             const long      nTol = pTols[ i ];
 
-            pMinR[ i ] = MinMax( (long) rCol.GetRed() - nTol, 0, 255 );
-            pMaxR[ i ] = MinMax( (long) rCol.GetRed() + nTol, 0, 255 );
-            pMinG[ i ] = MinMax( (long) rCol.GetGreen() - nTol, 0, 255 );
-            pMaxG[ i ] = MinMax( (long) rCol.GetGreen() + nTol, 0, 255 );
-            pMinB[ i ] = MinMax( (long) rCol.GetBlue() - nTol, 0, 255 );
-            pMaxB[ i ] = MinMax( (long) rCol.GetBlue() + nTol, 0, 255 );
+            pMinR[ i ] = MinMax<long>(rCol.GetRed() - nTol, 0, 255);
+            pMaxR[ i ] = MinMax<long>(rCol.GetRed() + nTol, 0, 255);
+            pMinG[ i ] = MinMax<long>(rCol.GetGreen() - nTol, 0, 255);
+            pMaxG[ i ] = MinMax<long>(rCol.GetGreen() + nTol, 0, 255);
+            pMinB[ i ] = MinMax<long>(rCol.GetBlue() - nTol, 0, 255);
+            pMaxB[ i ] = MinMax<long>(rCol.GetBlue() + nTol, 0, 255);
         }
 
         if( pAcc->HasPalette() )
commit 2b60ce6d9360e522d9e24ea834b4e8690970901f
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Thu Jul 7 20:23:41 2016 +0100

    tdf#99512 - opencl - restrict scope of vlookup optimization to doubles.
    
    Change-Id: Iab7316cb167f34c13adafe142af0fdd73eb7d04c
    Reviewed-on: https://gerrit.libreoffice.org/27100
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
    (cherry picked from commit dead5dc1ae3baab5e25d641322d138dd3d242bff)
    Reviewed-on: https://gerrit.libreoffice.org/27105
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 9613bb90986277f3a222bea9a6d6d11f53a36622)

diff --git a/sc/source/core/opencl/op_spreadsheet.cxx b/sc/source/core/opencl/op_spreadsheet.cxx
index c18b2ba..243d299 100644
--- a/sc/source/core/opencl/op_spreadsheet.cxx
+++ b/sc/source/core/opencl/op_spreadsheet.cxx
@@ -45,12 +45,41 @@ void OpVLookup::GenSlidingWindowFunction(std::stringstream &ss,
     CheckSubArgumentIsNan(ss,vSubArguments,arg++);
     int secondParaWidth = 1;
 
+    // tdf#99512 - for now only allow non-dynamic indicees (the
+    // common-case) to validate consistent return types vs. the input.
+    int index = 0;
+    int indexArg = vSubArguments.size() - 2;
+    if (vSubArguments[indexArg]->GetFormulaToken()->GetType() == formula::svDouble)
+    {
+        const formula::FormulaDoubleToken *dblToken = static_cast<const FormulaDoubleToken *>(vSubArguments[indexArg]->GetFormulaToken());
+        index = ::rtl::math::approxFloor(dblToken->GetDouble());
+    }
+
     if (vSubArguments[1]->GetFormulaToken()->GetType() == formula::svDoubleVectorRef)
     {
         FormulaToken *tmpCur = vSubArguments[1]->GetFormulaToken();
         const formula::DoubleVectorRefToken*pCurDVR = static_cast<const formula::DoubleVectorRefToken *>(tmpCur);
-        secondParaWidth = pCurDVR->GetArrays().size();
+        const std::vector<VectorRefArray> items = pCurDVR->GetArrays();
+
+        secondParaWidth = items.size();
+
+        if (index < 1 || index > secondParaWidth)
+            throw Unhandled(__FILE__, __LINE__); // oob index.
+
+        if (items[index - 1].mpStringArray)
+        {
+            rtl_uString **pStrings = items[index - 1].mpStringArray;
+            for (size_t i = 0; i < pCurDVR->GetArrayLength(); ++i)
+            {
+                if (pStrings[i] != nullptr)
+                {   // TODO: the GroupTokenConverter should do better.
+                    throw Unhandled(__FILE__, __LINE__); // mixed arguments.
+                }
+            }
+        }
     }
+    else
+        throw Unhandled(__FILE__, __LINE__); // unusual vlookup.
 
     arg += secondParaWidth;
     CheckSubArgumentIsNan(ss,vSubArguments,arg++);
commit ae5dbc2de4adb7b24f4c07f4090d8b88fe717ede
Author: Winfried Donkers <winfrieddonkers at libreoffice.org>
Date:   Wed Jul 6 12:48:08 2016 +0200

    tdf#100753 propagate error with VAR and STDEV functions.
    
    Change-Id: I1b3ece177f5586f5cd64a34d16193d01d4bd5bd9
    Reviewed-on: https://gerrit.libreoffice.org/26979
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Eike Rathke <erack at redhat.com>
    (cherry picked from commit b9c9bf666b4eb7ee4568fe155a2c8b50a02c4ad5)
    Reviewed-on: https://gerrit.libreoffice.org/27061
    (cherry picked from commit 88065eebdf9bc557b2c5d982b0beacb19ef2ad36)

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index fa9d70a..143aec6 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3613,6 +3613,8 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
             case svDouble :
             {
                 fVal = GetDouble();
+                if ( nGlobalError )
+                    return;
                 values.push_back(fVal);
                 fSum    += fVal;
                 rValCount++;
@@ -3625,6 +3627,8 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
                 if (aCell.hasNumeric())
                 {
                     fVal = GetCellValue(aAdr, aCell);
+                    if ( nGlobalError )
+                        return;
                     values.push_back(fVal);
                     fSum += fVal;
                     rValCount++;
@@ -3652,6 +3656,11 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
                     }
                     while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
                 }
+                if ( nErr )
+                {
+                    SetError(nErr);
+                    return;
+                }
             }
             break;
             case svMatrix :
commit 60d7bb75b07a7585a53e08effae7399ab424225c
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Jul 8 12:48:17 2016 +0100

    Resolves: tdf#100713 on cancel curData points to deleted parents vector entry
    
    Change-Id: Ic2f313c357ce9526eb045791e2d27451e52a7572
    (cherry picked from commit 17cb84338d6921d012af1e1245f434f90bc25142)
    Reviewed-on: https://gerrit.libreoffice.org/27041
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Björn Michaelsen <bjoern.michaelsen at canonical.com>
    (cherry picked from commit bfbb5906bf85f7e4134d19fbe80216c549185e69)

diff --git a/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx
index 5b97ad9..279a677 100644
--- a/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx
+++ b/desktop/source/deployment/gui/dp_gui_updateinstalldialog.cxx
@@ -91,7 +91,7 @@ private:
 
     virtual void execute() override;
     void downloadExtensions();
-    void download(OUString const & aUrls, UpdateData & aUpdatData);
+    bool download(OUString const & aUrls, UpdateData & aUpdatData);
     void installExtensions();
     void removeTempDownloads();
 
@@ -391,8 +391,8 @@ void UpdateInstallDialog::Thread::downloadExtensions()
                 try
                 {
                     OSL_ENSURE(!seqDownloadURLs[j].isEmpty(), "Download URL is empty!");
-                    download(seqDownloadURLs[j], curData);
-                    if (!curData.sLocalURL.isEmpty())
+                    bool bCancelled = download(seqDownloadURLs[j], curData);
+                    if (bCancelled || !curData.sLocalURL.isEmpty())
                         break;
                 }
                 catch ( cssu::Exception & e )
@@ -578,12 +578,12 @@ void UpdateInstallDialog::Thread::removeTempDownloads()
     }
 }
 
-void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData)
+bool UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData)
 {
     {
         SolarMutexGuard g;
         if (m_stop) {
-            return;
+            return m_stop;
         }
     }
 
@@ -617,12 +617,14 @@ void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, Update
         {
             SolarMutexGuard g;
             if (m_stop) {
-                return;
+                return m_stop;
             }
             //all errors should be handled by the command environment.
             aUpdateData.sLocalURL = destFolder + "/" + sTitle;
         }
     }
+
+    return m_stop;
 }
 
 UpdateCommandEnv::UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
commit bd97159740522841761ab224115929af28b89d4b
Author: Takeshi Abe <tabe at fixedpoint.jp>
Date:   Fri Jul 8 15:54:24 2016 +0900

    starmath: Fix missing negation
    
    which was a regression from fa614231733800f4a961b77e36c86f8840d12251.
    
    Change-Id: Ia7bab72dbd6f82519024809cf6384e1442a02327
    Reviewed-on: https://gerrit.libreoffice.org/27033
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: David Tardon <dtardon at redhat.com>
    (cherry picked from commit 2fcb8022a22b55b6680af57f2b101d56a3d88e36)
    (cherry picked from commit ccc92a4706c2fa72a17e736cff8fbf70cec2b2f9)

diff --git a/starmath/source/node.cxx b/starmath/source/node.cxx
index 1bf8814..27409a9 100644
--- a/starmath/source/node.cxx
+++ b/starmath/source/node.cxx
@@ -2891,7 +2891,7 @@ void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell
         else if (nStyle == 2)
         {
             const OUString& rTmp(GetText());
-            if (rTmp.isEmpty())
+            if (!rTmp.isEmpty())
             {
                 static const sal_Unicode cUppercaseAlpha = 0x0391;
                 static const sal_Unicode cUppercaseOmega = 0x03A9;


More information about the Libreoffice-commits mailing list