[Libreoffice-commits] core.git: Branch 'private/tml/splitgroup' - 67 commits - avmedia/source bridges/source canvas/source configure.ac connectivity/source dictionaries editeng/source external/boost external/hunspell external/libebook external/libmspub external/liborcus external/libpagemaker external/librevenge filter/qa filter/source fpicker/source framework/source icon-themes/sifr include/clew include/oox include/opencl include/svl include/svx include/vcl oox/source opencl/source sc/inc sc/source sc/uiconfig sd/qa sd/source sfx2/uiconfig slideshow/source solenv/gbuild svl/source svtools/source svx/inc svx/source sw/inc sw/qa sw/source vcl/inc vcl/opengl vcl/qa vcl/source vcl/unx vcl/win vcl/workben

Tor Lillqvist tml at collabora.com
Tue Sep 15 05:35:37 PDT 2015


Rebased ref, commits from common ancestor:
commit 3671c5124dc9de37be3cf4c65afde5f9d3bb8406
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Sep 15 13:27:18 2015 +0300

    Use heuristic to find out whether to split formula groups for OpenCL
    
    It is necessary to not perform too large OpenCL computations on some
    low-end devices on Windows as the driver will be unresponsive too
    long.  On these devices, the CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT is
    4, while for more performant devices it is 1 or 8.

diff --git a/include/clew/clew.h b/include/clew/clew.h
index 94b6c29..e5cfaf0 100644
--- a/include/clew/clew.h
+++ b/include/clew/clew.h
@@ -416,6 +416,7 @@ typedef struct _cl_image_format {
 
 // cl_device_info
 #define CL_DEVICE_MAX_COMPUTE_UNITS                 0x1002
+#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT      0x100A
 #define CL_DEVICE_MAX_CLOCK_FREQUENCY               0x100C
 #define CL_DEVICE_GLOBAL_MEM_SIZE                   0x101F
 #define CL_DEVICE_NAME                              0x102B
diff --git a/include/opencl/openclwrapper.hxx b/include/opencl/openclwrapper.hxx
index 75ecbc8..e3f967e 100644
--- a/include/opencl/openclwrapper.hxx
+++ b/include/opencl/openclwrapper.hxx
@@ -52,6 +52,7 @@ struct GPUEnv
     int mnCmdQueuePos;
     bool mnKhrFp64Flag;
     bool mnAmdFp64Flag;
+    cl_uint mnPreferredVectorWidthFloat;
 };
 
 extern OPENCL_DLLPUBLIC GPUEnv gpuEnv;
diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx
index 5574d2c..9d03a27 100644
--- a/opencl/source/openclwrapper.cxx
+++ b/opencl/source/openclwrapper.cxx
@@ -501,6 +501,11 @@ bool initOpenCLRunEnv( GPUEnv *gpuInfo )
     gpuInfo->mnKhrFp64Flag = bKhrFp64;
     gpuInfo->mnAmdFp64Flag = bAmdFp64;
 
+    gpuInfo->mnPreferredVectorWidthFloat = 0;
+
+    clGetDeviceInfo(gpuInfo->mpArryDevsID[0], CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint),
+                    &gpuInfo->mnPreferredVectorWidthFloat, NULL);
+
     return false;
 }
 
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 774aed3..7f8180f 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -55,6 +55,7 @@
 #include "types.hxx"
 #include "scopetools.hxx"
 #include "refupdatecontext.hxx"
+#include <opencl/openclwrapper.hxx>
 #include <tokenstringcontext.hxx>
 #include <refhint.hxx>
 #include <listenerquery.hxx>
@@ -3838,10 +3839,21 @@ bool ScFormulaCell::InterpretFormulaGroup()
 
     // Should obviously be based on some heuristics based on the kind
     // of OpenCL device or some of its properties.
-    const int MAXGROUPLENGTH = (std::getenv("MAXGROUPLENGTH") ? std::atoi(std::getenv("MAXGROUPLENGTH")) : 1000);
+    int nMaxGroupLength = INT_MAX;
+
+#ifdef WNT
+    // Heuristic: Certain old low-end OpenCL implementations don't
+    // work for us with too large group lengths. 1000 was determined
+    // empirically to be a good compromise.
+    if (opencl::gpuEnv.mnPreferredVectorWidthFloat == 4)
+        nMaxGroupLength = 1000;
+#endif
+
+    if (std::getenv("SC_MAX_GROUP_LENGTH"))
+        nMaxGroupLength = std::atoi(std::getenv("SC_MAX_GROUP_LENGTH"));
 
     int nNumOnePlus;
-    const int nNumParts = splitup(GetSharedLength(), MAXGROUPLENGTH, nNumOnePlus);
+    const int nNumParts = splitup(GetSharedLength(), nMaxGroupLength, nNumOnePlus);
 
     int nOffset = 0;
     int nCurChunkSize;
@@ -3856,7 +3868,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
             xGroup = mxGroup;
         else
         {
-            // Possibly incorrect hack
+            // Ugly hack
             xGroup = new ScFormulaCellGroup();
             xGroup->mpTopCell = mxGroup->mpTopCell;
             xGroup->mpTopCell->aPos = aOrigPos;
commit 6c27bc9b90deff8b110f6add51c9cd230d32e8bf
Author: Tor Lillqvist <tml at collabora.com>
Date:   Thu Sep 10 21:58:28 2015 +0300

    Replace with real commit message if/when going into public branch
    
    Change-Id: Iec1416441e0323724c9b64589310faa61a7da5f0

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index eb2b374..774aed3 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -20,6 +20,7 @@
 #include <sal/config.h>
 
 #include <cassert>
+#include <cstdlib>
 
 #include "formulacell.hxx"
 #include "grouptokenconverter.hxx"
@@ -3770,6 +3771,36 @@ ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell& r
     return bInvariant ? EqualInvariant : EqualRelativeRef;
 }
 
+namespace {
+
+// Split N into optimally equal-sized pieces, each not larger than K.
+// Return value P is number of pieces. A returns the number of pieces
+// one larger than N/P, 0..P-1.
+
+int splitup(int N, int K, int& A)
+{
+    assert(N > 0);
+    assert(K > 0);
+
+    A = 0;
+
+    if (N <= K)
+        return 1;
+
+    const int ideal_num_parts = N / K;
+    if (ideal_num_parts * K == N)
+        return ideal_num_parts;
+
+    const int num_parts = ideal_num_parts + 1;
+    const int nominal_part_size = N / num_parts;
+
+    A = N - num_parts * nominal_part_size;
+
+    return num_parts;
+}
+
+} // anonymous namespace
+
 bool ScFormulaCell::InterpretFormulaGroup()
 {
     if (!officecfg::Office::Common::Misc::UseOpenCL::get())
@@ -3805,30 +3836,84 @@ bool ScFormulaCell::InterpretFormulaGroup()
     if (mxGroup->mbInvariant && false)
         return InterpretInvariantFormulaGroup();
 
-    ScTokenArray aCode;
-    ScAddress aTopPos = aPos;
-    aTopPos.SetRow(mxGroup->mpTopCell->aPos.Row());
-    ScGroupTokenConverter aConverter(aCode, *pDocument, *this, mxGroup->mpTopCell->aPos);
-    std::vector<ScTokenArray*> aLoopControl;
-    if (!aConverter.convert(*pCode, aLoopControl))
-    {
-        SAL_INFO("sc.opencl", "conversion of group " << this << " failed, disabling");
-        mxGroup->meCalcState = sc::GroupCalcDisabled;
-        return false;
-    }
+    // Should obviously be based on some heuristics based on the kind
+    // of OpenCL device or some of its properties.
+    const int MAXGROUPLENGTH = (std::getenv("MAXGROUPLENGTH") ? std::atoi(std::getenv("MAXGROUPLENGTH")) : 1000);
 
-    // The converted code does not have RPN tokens yet.  The interpreter will
-    // generate them.
-    mxGroup->meCalcState = sc::GroupCalcRunning;
-    sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic();
-    if (pInterpreter == NULL ||
-        !pInterpreter->interpret(*pDocument, mxGroup->mpTopCell->aPos, mxGroup, aCode))
+    int nNumOnePlus;
+    const int nNumParts = splitup(GetSharedLength(), MAXGROUPLENGTH, nNumOnePlus);
+
+    int nOffset = 0;
+    int nCurChunkSize;
+    ScAddress aOrigPos = mxGroup->mpTopCell->aPos;
+    for (int i = 0; i < nNumParts; i++, nOffset += nCurChunkSize)
     {
-        SAL_INFO("sc.opencl", "interpreting group " << mxGroup << " (state " << (int) mxGroup->meCalcState << ") failed, disabling");
-        mxGroup->meCalcState = sc::GroupCalcDisabled;
-        return false;
+        nCurChunkSize = GetSharedLength()/nNumParts + (i < nNumOnePlus ? 1 : 0);
+
+        ScFormulaCellGroupRef xGroup;
+
+        if (nNumParts == 1)
+            xGroup = mxGroup;
+        else
+        {
+            // Possibly incorrect hack
+            xGroup = new ScFormulaCellGroup();
+            xGroup->mpTopCell = mxGroup->mpTopCell;
+            xGroup->mpTopCell->aPos = aOrigPos;
+            xGroup->mpTopCell->aPos.IncRow(nOffset);
+            xGroup->mbInvariant = mxGroup->mbInvariant;
+            xGroup->mnLength = nCurChunkSize;
+            xGroup->mpCode = mxGroup->mpCode;
+        }
+
+        ScTokenArray aCode;
+        ScGroupTokenConverter aConverter(aCode, *pDocument, *this, xGroup->mpTopCell->aPos);
+        std::vector<ScTokenArray*> aLoopControl;
+        if (!aConverter.convert(*pCode, aLoopControl))
+        {
+            SAL_INFO("sc.opencl", "conversion of group " << this << " failed, disabling");
+            mxGroup->meCalcState = sc::GroupCalcDisabled;
+
+            // Undo the hack above
+            if (nNumParts > 1)
+            {
+                mxGroup->mpTopCell->aPos = aOrigPos;
+                xGroup->mpTopCell = NULL;
+                xGroup->mpCode = NULL;
+            }
+
+            return false;
+        }
+
+        // The converted code does not have RPN tokens yet.  The interpreter will
+        // generate them.
+        xGroup->meCalcState = mxGroup->meCalcState = sc::GroupCalcRunning;
+        sc::FormulaGroupInterpreter *pInterpreter = sc::FormulaGroupInterpreter::getStatic();
+        if (pInterpreter == NULL ||
+            !pInterpreter->interpret(*pDocument, xGroup->mpTopCell->aPos, xGroup, aCode))
+        {
+            SAL_INFO("sc.opencl", "interpreting group " << mxGroup << " (state " << (int) mxGroup->meCalcState << ") failed, disabling");
+            mxGroup->meCalcState = sc::GroupCalcDisabled;
+
+            // Undo the hack above
+            if (nNumParts > 1)
+            {
+                mxGroup->mpTopCell->aPos = aOrigPos;
+                xGroup->mpTopCell = NULL;
+                xGroup->mpCode = NULL;
+            }
+
+            return false;
+        }
+        if (nNumParts > 1)
+        {
+            xGroup->mpTopCell = NULL;
+            xGroup->mpCode = NULL;
+        }
     }
 
+    if (nNumParts > 1)
+        mxGroup->mpTopCell->aPos = aOrigPos;
     mxGroup->meCalcState = sc::GroupCalcEnabled;
     return true;
 }
commit 788fb4a0152d64c431c0c6062045a742ef80f40b
Author: Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
Date:   Tue Sep 15 11:47:20 2015 +0200

    tdf#94198 Printer missing from tooltip
    
    Need to update the tooltip also on state change.
    This partially reverts the fix for tdf#83558, 1fb8724f9834dbc07b741eeed31b31347bc0c2a1
    Verified that the fix for tdf#83558 still works.
    
    Change-Id: I023a5e4b101dc91522f19b0d3ed2ed0c4a47e64b
    Reviewed-on: https://gerrit.libreoffice.org/18586
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>

diff --git a/framework/source/uielement/generictoolbarcontroller.cxx b/framework/source/uielement/generictoolbarcontroller.cxx
index 8b37282..183da37 100644
--- a/framework/source/uielement/generictoolbarcontroller.cxx
+++ b/framework/source/uielement/generictoolbarcontroller.cxx
@@ -244,6 +244,7 @@ throw ( RuntimeException, std::exception )
                     aStrValue = aTmp;
                 }
                 m_pToolbar->SetItemText( m_nID, aStrValue );
+                m_pToolbar->SetQuickHelpText( m_nID, aStrValue );
             }
 
             if ( m_bMadeInvisible )
commit eea951d8de4ababb6e81d28221501e7bc3060b57
Author: Tomáš Chvátal <tchvatal at suse.com>
Date:   Tue Sep 15 11:43:45 2015 +0200

    KDE4Filedialog check should include cstdlib
    
    Otherwise this would needlessly fail on some compilers.
    
    Change-Id: I4e46e9e452de0703b6556cd55e4606b02be5c41c
    Reviewed-on: https://gerrit.libreoffice.org/18584
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Michael Stahl <mstahl at redhat.com>

diff --git a/configure.ac b/configure.ac
index c6f7b8d..afd48d64 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11318,6 +11318,7 @@ int main(int argc, char **argv) {
 
             AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #define SAL_OVERRIDE
+#include <cstdlib>
 #include "tst_exclude_socket_notifiers.moc"
 
 int main(int argc, char *argv[])
@@ -11351,6 +11352,7 @@ int main(int argc, char *argv[])
 
             AC_RUN_IFELSE([AC_LANG_SOURCE([[
 #define SAL_OVERRIDE
+#include <cstdlib>
 #include "tst_exclude_posted_events.moc"
 
 int main(int argc, char *argv[])
commit 93e82fa537362eb5a10b46035772c3a016fba53a
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Sep 11 13:46:39 2015 +0100

    Resolves: rhbz#1261421 crash on mashing hangul korean keyboard
    
    Change-Id: Ie066c7f83ad15bec198f2091a3b084468c502766
    (cherry picked from commit 064fd8342111bc62ba646e439c235bd495587a4a)
    Reviewed-on: https://gerrit.libreoffice.org/18499
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/external/hunspell/UnpackedTarball_hunspell.mk b/external/hunspell/UnpackedTarball_hunspell.mk
index ecf7856..6ad31dd 100644
--- a/external/hunspell/UnpackedTarball_hunspell.mk
+++ b/external/hunspell/UnpackedTarball_hunspell.mk
@@ -20,6 +20,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,hunspell,\
 	external/hunspell/hunspell-fdo48017-wfopen.patch \
 	external/hunspell/hunspell-morph-overflow.patch \
 	external/hunspell/ubsan.patch.0 \
+	external/hunspell/hunspell-1.3.3-rhbz1261421.patch \
 ))
 
 ifeq ($(COM),MSC)
diff --git a/external/hunspell/hunspell-1.3.3-rhbz1261421.patch b/external/hunspell/hunspell-1.3.3-rhbz1261421.patch
new file mode 100644
index 0000000..4354dd0
--- /dev/null
+++ b/external/hunspell/hunspell-1.3.3-rhbz1261421.patch
@@ -0,0 +1,191 @@
+From 97e079a23d459aeb6e64435350d7710c90dbca85 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm at redhat.com>
+Date: Fri, 11 Sep 2015 13:28:52 +0100
+Subject: [PATCH] Resolves: rhbz#1261421 crash on mashing hangul korean
+ keyboard
+
+---
+ src/hunspell/hunspell.cxx | 69 +++++++++++++++++++++++++++++++++++------------
+ src/hunspell/hunspell.hxx |  4 ++-
+ src/hunspell/replist.cxx  | 18 ++++++++++---
+ src/hunspell/replist.hxx  |  2 ++
+ src/tools/hunspell.cxx    |  2 +-
+ 6 files changed, 78 insertions(+), 24 deletions(-)
+
+diff --git a/src/hunspell/hunspell.cxx b/src/hunspell/hunspell.cxx
+index 7fae54b..d8ef357 100644
+--- misc/hunspell-1.3.3/src/hunspell/hunspell.cxx
++++ misc/build/hunspell-1.3.3/src/hunspell/hunspell.cxx
+@@ -12,6 +12,7 @@
+ #endif
+ #include "csutil.hxx"
+ 
++#include <limits>
+ #include <string>
+ 
+ Hunspell::Hunspell(const char * affpath, const char * dpath, const char * key)
+@@ -349,8 +350,13 @@ int Hunspell::spell(const char * word, int * info, char ** root)
+ 
+   // input conversion
+   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
+-  if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
+-  else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
++  int convstatus = rl ? rl->conv(word, wspace, MAXWORDUTF8LEN) : 0;
++  if (convstatus < 0)
++    return 0;
++  else if (convstatus > 0)
++    wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
++  else
++    wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
+ 
+   if (wl == 0 || maxdic == 0) return 1;
+   if (root) *root = NULL;
+@@ -702,8 +708,13 @@ int Hunspell::suggest(char*** slst, const char * word)
+ 
+   // input conversion
+   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
+-  if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
+-  else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
++  int convstatus = rl ? rl->conv(word, wspace, MAXWORDUTF8LEN) : 0;
++  if (convstatus < 0)
++    return 0;
++  else if (convstatus > 0)
++    wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
++  else
++    wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
+ 
+   if (wl == 0) return 0;
+   int ns = 0;
+@@ -1020,7 +1031,7 @@ int Hunspell::suggest(char*** slst, const char * word)
+   // output conversion
+   rl = (pAMgr) ? pAMgr->get_oconvtable() : NULL;
+   for (int j = 0; rl && j < ns; j++) {
+-    if (rl->conv((*slst)[j], wspace)) {
++    if (rl->conv((*slst)[j], wspace, MAXWORDUTF8LEN) > 0) {
+       free((*slst)[j]);
+       (*slst)[j] = mystrdup(wspace);
+     }
+@@ -1395,8 +1406,13 @@ int Hunspell::analyze(char*** slst, const char * word)
+ 
+   // input conversion
+   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
+-  if (rl && rl->conv(word, wspace)) wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
+-  else wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
++  int convstatus = rl ? rl->conv(word, wspace, MAXWORDUTF8LEN) : 0;
++  if (convstatus < 0)
++    return 0;
++  else if (convstatus > 0)
++    wl = cleanword2(cw, wspace, unicw, &nc, &captype, &abbv);
++  else
++    wl = cleanword2(cw, word, unicw, &nc, &captype, &abbv);
+ 
+   if (wl == 0) {
+       if (abbv) {
+@@ -1684,12 +1700,16 @@ int Hunspell::get_langnum() const
+    return langnum;
+ }
+ 
+-int Hunspell::input_conv(const char * word, char * dest)
++int Hunspell::input_conv(const char * word, char * dest, size_t destsize)
+ {
+   RepList * rl = (pAMgr) ? pAMgr->get_iconvtable() : NULL;
+-  return (rl && rl->conv(word, dest));
++  return (rl && rl->conv(word, dest, destsize) > 0);
+ }
+ 
++int Hunspell::input_conv(const char * word, char * dest)
++{
++  return input_conv(word, dest, std::numeric_limits<std::size_t>::max());
++}
+ 
+ // return the beginning of the element (attr == NULL) or the attribute
+ const char * Hunspell::get_xml_pos(const char * s, const char * attr)
+diff --git a/src/hunspell/hunspell.hxx b/src/hunspell/hunspell.hxx
+index e62f0dd..0b5ad2e 100644
+--- misc/hunspell-1.3.3/src/hunspell/hunspell.hxx
++++ misc/build/hunspell-1.3.3/src/hunspell/hunspell.hxx
+@@ -226,7 +226,9 @@ public:
+ 
+   /* need for putdic */
+   int input_conv(const char * word, char * dest);
+-  
++  // ^^-deprecated, use this-vv"
++  int input_conv(const char * word, char * dest, size_t destsize);
++ 
+   /* experimental and deprecated functions */
+ 
+ #ifdef HUNSPELL_EXPERIMENTAL
+diff --git a/src/hunspell/replist.cxx b/src/hunspell/replist.cxx
+index b9b1255..bac3e06 100644
+--- misc/hunspell-1.3.3/src/hunspell/replist.cxx
++++ misc/build/hunspell-1.3.3/src/hunspell/replist.cxx
+@@ -74,6 +74,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <stdio.h>
++#include <limits>
+ 
+ #include "replist.hxx"
+ #include "csutil.hxx"
+@@ -139,19 +140,30 @@ int RepList::add(char * pat1, char * pat2) {
+     return 0;
+ }
+ 
+-int RepList::conv(const char * word, char * dest) {
++int RepList::conv(const char * word, char * dest, size_t destsize) {
+     int stl = 0;
+     int change = 0;
+     for (size_t i = 0; i < strlen(word); i++) {
+         int n = near(word + i);
+         int l = match(word + i, n);
+         if (l) {
++          size_t replen = strlen(dat[n]->pattern2);
++          if (stl+replen >= destsize)
++            return -1;
+           strcpy(dest + stl, dat[n]->pattern2);
+-          stl += strlen(dat[n]->pattern2);
++          stl += replen;
+           i += l - 1;
+           change = 1;
+-        } else dest[stl++] = word[i];
++        } else {
++          if (stl+1 >= destsize)
++            return -1;
++          dest[stl++] = word[i];
++        }
+     }
+     dest[stl] = '\0';
+     return change;
+ }
++
++int RepList::conv(const char * word, char * dest) {
++    return conv(word, dest, std::numeric_limits<std::size_t>::max());
++}
+diff --git a/src/hunspell/replist.hxx b/src/hunspell/replist.hxx
+index 1e3d6e4..e418298 100644
+--- misc/hunspell-1.3.3/src/hunspell/replist.hxx
++++ misc/build/hunspell-1.3.3/src/hunspell/replist.hxx
+@@ -99,5 +99,7 @@ public:
+     int near(const char * word);
+     int match(const char * word, int n);
+     int conv(const char * word, char * dest);
++    // ^^-deprecated, use this-vv"
++    int conv(const char * word, char * dest, size_t destsize);
+ };
+ #endif
+diff --git a/src/tools/hunspell.cxx b/src/tools/hunspell.cxx
+index 6124ac4..1b50fe1 100644
+--- misc/hunspell-1.3.3/src/tools/hunspell.cxx
++++ misc/build/hunspell-1.3.3/src/tools/hunspell.cxx
+@@ -524,7 +524,7 @@ int putdic(char * word, Hunspell * pMS)
+     
+     word = chenc(word, ui_enc, dic_enc[0]);
+ 
+-    if(pMS->input_conv(word, buf)) word = buf;
++    if(pMS->input_conv(word, buf, MAXLNLEN)) word = buf;
+     
+     int ret;
+     
+-- 
+2.4.0
+
commit 5b9501f6da42ba5b9d1b3c702d527bf8795cdd7c
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Wed Sep 9 09:45:58 2015 +0100

    Resolves: tdf#93887 distinguish between empty selection lost selection
    
    Change-Id: Id0be728602b3c58b2853ff464336d68303531efe
    (cherry picked from commit f3f1919aa4eca2f6180649eda43bcb813b1f0450)
    Reviewed-on: https://gerrit.libreoffice.org/18434
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>
    Tested-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/vcl/unx/gtk3/app/gtk3gtkinst.cxx b/vcl/unx/gtk3/app/gtk3gtkinst.cxx
index d8614df..f8fd6a6 100644
--- a/vcl/unx/gtk3/app/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/app/gtk3gtkinst.cxx
@@ -372,8 +372,11 @@ sal_Bool VclGtkClipboard::supportsService( const OUString& ServiceName ) throw(
 
 Reference< css::datatransfer::XTransferable > VclGtkClipboard::getContents() throw( RuntimeException, std::exception )
 {
-    if (!m_aContents.is())
+    if (G_OBJECT(m_pOwner) != gtk_clipboard_get_owner(gtk_clipboard_get(m_nSelection)) &&
+        !m_aContents.is())
     {
+        //tdf#93887 This is the system clipboard/selection. We fetch it when we are not
+        //the owner of the clipboard and have not already fetched it.
         m_aContents = new GtkTransferable(m_nSelection);
     }
     return m_aContents;
commit 5eb91d291d383c519c5b931bc6218c0c5caa8f3d
Author: Szymon Kłos <eszkadev at gmail.com>
Date:   Thu Jul 23 10:54:44 2015 +0200

    Resolves: tdf#93778 fixed crash
    
    While opening folders in SvtFileView using doubleclick,
    sometimes GtkSalFrame::gestureLongPress method is
    executed with a null frame pointer and LO crashes.
    I noticed this only with remote dirs, probably this
    bug occurs only when the doubleclick handler routine
    takes a lot of time.
    
    (cherry picked from commit db33c7853e12e9593a530ce2327e9662bcab1480)
    
    Change-Id: I432046994b3e1662bd7e499681bd20e9696b2d52
    Reviewed-on: https://gerrit.libreoffice.org/18571
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/unx/gtk/window/gtksalframe.cxx b/vcl/unx/gtk/window/gtksalframe.cxx
index 7f8570e..347497c 100644
--- a/vcl/unx/gtk/window/gtksalframe.cxx
+++ b/vcl/unx/gtk/window/gtksalframe.cxx
@@ -3541,15 +3541,18 @@ void GtkSalFrame::gestureLongPress(GtkGestureLongPress* gesture, gpointer frame)
 {
     GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
 
-    SalLongPressEvent aEvent;
+    if(pThis)
+    {
+        SalLongPressEvent aEvent;
 
-    gdouble x, y;
-    GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
-    gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
-    aEvent.mnX = x;
-    aEvent.mnY = y;
+        gdouble x, y;
+        GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
+        gtk_gesture_get_point(GTK_GESTURE(gesture), sequence, &x, &y);
+        aEvent.mnX = x;
+        aEvent.mnY = y;
 
-    pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
+        pThis->CallCallback(SALEVENT_LONGPRESS, &aEvent);
+    }
 }
 
 #endif
commit 868ddebc1ad874ca17e0b7bee873dfeb5f6521ea
Author: Julien Nabet <serval2412 at yahoo.fr>
Date:   Thu Sep 3 22:37:31 2015 +0200

    tdf#92794: '$' should be replaced in error dialog of addressbook
    
    Change-Id: Ic57611be96f160037fbff2e9452f9206083c80e4
    Reviewed-on: https://gerrit.libreoffice.org/18324
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 01547985ceee8c199dc189071845ef5fcda11782)
    Reviewed-on: https://gerrit.libreoffice.org/18520

diff --git a/connectivity/source/drivers/mork/MConnection.cxx b/connectivity/source/drivers/mork/MConnection.cxx
index 8112a16..3f8baaf 100644
--- a/connectivity/source/drivers/mork/MConnection.cxx
+++ b/connectivity/source/drivers/mork/MConnection.cxx
@@ -143,7 +143,9 @@ void OConnection::construct(const OUString& url,const Sequence< PropertyValue >&
     if (!m_pBook->open(strPath.getStr()))
     {
         SAL_WARN("connectivity.mork", "Can not parse abook mork file: " << strPath);
-        throwGenericSQLException( STR_COULD_NOT_LOAD_FILE, *this );
+        const OUString sError( getResources().getResourceStringWithSubstitution(
+            STR_COULD_NOT_LOAD_FILE, "$filename$", abook));
+        ::dbtools::throwGenericSQLException( sError, *this );
     }
 
     // read history only in production
@@ -153,7 +155,9 @@ void OConnection::construct(const OUString& url,const Sequence< PropertyValue >&
         if (!m_pHistory->open(strPath.getStr()))
         {
             SAL_WARN("connectivity.mork", "Can not parse history mork file: " << strPath);
-            throwGenericSQLException( STR_COULD_NOT_LOAD_FILE, *this );
+            const OUString sError( getResources().getResourceStringWithSubstitution(
+                STR_COULD_NOT_LOAD_FILE, "$filename$", history));
+            ::dbtools::throwGenericSQLException( sError, *this );
         }
     }
 
commit 7108b46723750dd390d28afda37ecf1e85581f6a
Author: Katarina Behrens <Katarina.Behrens at cib.de>
Date:   Thu Sep 10 13:22:03 2015 +0200

    tdf#94037: Don't try to manipulate non-existent widget container
    
    Regression from commit 8b7799972a95da50e1e92748, which replaced
    named GtkFrame with GtkBox, but didn't rename the box accordingly.
    
    Change-Id: I321dbee05faded81dbf575bca3c578ecb09f1a3e
    Reviewed-on: https://gerrit.libreoffice.org/18562
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/sc/uiconfig/scalc/ui/protectsheetdlg.ui b/sc/uiconfig/scalc/ui/protectsheetdlg.ui
index 388c289..ee0d7c3 100644
--- a/sc/uiconfig/scalc/ui/protectsheetdlg.ui
+++ b/sc/uiconfig/scalc/ui/protectsheetdlg.ui
@@ -180,7 +180,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkBox" id="box3">
+              <object class="GtkBox" id="options">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
commit 07e60c9fe65002f698524a838150c457daef2d77
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Fri Sep 11 15:38:01 2015 +0100

    check stream status more often
    
    Change-Id: I233c2fff9c06a81117f8114ccee83b53ea4026db
    (cherry picked from commit b43e03353aeb04ed74a272d98df03dd7c20f3478)
    Reviewed-on: https://gerrit.libreoffice.org/18505
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: David Tardon <dtardon at redhat.com>

diff --git a/filter/qa/cppunit/data/ras/fail/hang-1.ras b/filter/qa/cppunit/data/ras/fail/hang-1.ras
new file mode 100644
index 0000000..44dec67
Binary files /dev/null and b/filter/qa/cppunit/data/ras/fail/hang-1.ras differ
diff --git a/filter/source/graphicfilter/iras/iras.cxx b/filter/source/graphicfilter/iras/iras.cxx
index 5877fa2..e3209bd 100644
--- a/filter/source/graphicfilter/iras/iras.cxx
+++ b/filter/source/graphicfilter/iras/iras.cxx
@@ -222,31 +222,43 @@ bool RASReader::ImplReadBody(BitmapWriteAccess * pAcc)
         case 1 :
             for (y = 0; y < mnHeight && mbStatus; ++y)
             {
-                for ( x = 0; x < mnWidth; x++ )
+                for (x = 0; x < mnWidth && mbStatus; ++x)
                 {
                     if (!(x & 7))
+                    {
                         nDat = ImplGetByte();
+                        if (!m_rRAS.good())
+                            mbStatus = false;
+                    }
                     pAcc->SetPixelIndex( y, x,
                         sal::static_int_cast< sal_uInt8 >(
                             nDat >> ( ( x & 7 ) ^ 7 )) );
                 }
-                if (!( ( x - 1 ) & 0x8 ) ) ImplGetByte();       // WORD ALIGNMENT ???
-                if (!m_rRAS.good())
-                    mbStatus = false;
+                if (!( ( x - 1 ) & 0x8 ) )
+                {
+                    ImplGetByte();       // WORD ALIGNMENT ???
+                    if (!m_rRAS.good())
+                        mbStatus = false;
+                }
             }
             break;
 
         case 8 :
             for (y = 0; y < mnHeight && mbStatus; ++y)
             {
-                for ( x = 0; x < mnWidth; x++ )
+                for (x = 0; x < mnWidth && mbStatus; ++x)
                 {
                     nDat = ImplGetByte();
                     pAcc->SetPixelIndex( y, x, nDat );
+                    if (!m_rRAS.good())
+                        mbStatus = false;
+                }
+                if ( x & 1 )
+                {
+                    ImplGetByte();                     // WORD ALIGNMENT ???
+                    if (!m_rRAS.good())
+                        mbStatus = false;
                 }
-                if ( x & 1 ) ImplGetByte();                     // WORD ALIGNMENT ???
-                if (!m_rRAS.good())
-                    mbStatus = false;
             }
             break;
 
@@ -257,7 +269,7 @@ bool RASReader::ImplReadBody(BitmapWriteAccess * pAcc)
                 case 24 :
                     for (y = 0; y < mnHeight && mbStatus; ++y)
                     {
-                        for ( x = 0; x < mnWidth; x++ )
+                        for (x = 0; x < mnWidth && mbStatus; ++x)
                         {
                             if ( mnType == RAS_TYPE_RGB_FORMAT )
                             {
@@ -272,17 +284,22 @@ bool RASReader::ImplReadBody(BitmapWriteAccess * pAcc)
                                 nRed = ImplGetByte();
                             }
                             pAcc->SetPixel ( y, x, BitmapColor( nRed, nGreen, nBlue ) );
+                            if (!m_rRAS.good())
+                                mbStatus = false;
+                        }
+                        if ( x & 1 )
+                        {
+                            ImplGetByte();                     // WORD ALIGNMENT ???
+                            if (!m_rRAS.good())
+                                mbStatus = false;
                         }
-                        if ( x & 1 ) ImplGetByte();                     // WORD ALIGNMENT ???
-                        if (!m_rRAS.good())
-                            mbStatus = false;
                     }
                     break;
 
                 case 32 :
                     for (y = 0; y < mnHeight && mbStatus; ++y)
                     {
-                        for ( x = 0; x < mnWidth; x++ )
+                        for (x = 0; x < mnWidth && mbStatus; ++x)
                         {
                             nDat = ImplGetByte();               // pad byte > nil
                             if ( mnType == RAS_TYPE_RGB_FORMAT )
@@ -298,9 +315,9 @@ bool RASReader::ImplReadBody(BitmapWriteAccess * pAcc)
                                 nRed = ImplGetByte();
                             }
                             pAcc->SetPixel ( y, x, BitmapColor( nRed, nGreen, nBlue ) );
+                            if (!m_rRAS.good())
+                                mbStatus = false;
                         }
-                        if (!m_rRAS.good())
-                            mbStatus = false;
                     }
                     break;
             }
commit c9e824687521ef2c3a90ba969627178b372d885c
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Sep 10 09:24:13 2015 +0100

    fix size check related hang
    
    Change-Id: I3e8aa5c48ba802cd363688502b44e27bfdf67f01
    (cherry picked from commit b02f1c58e7bb8b6c9381107431557d3f39794fe0)
    Reviewed-on: https://gerrit.libreoffice.org/18464
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: David Tardon <dtardon at redhat.com>
    Tested-by: David Tardon <dtardon at redhat.com>

diff --git a/filter/qa/cppunit/data/psd/pass/hang-1.psd b/filter/qa/cppunit/data/psd/pass/hang-1.psd
new file mode 100644
index 0000000..8f557dd
Binary files /dev/null and b/filter/qa/cppunit/data/psd/pass/hang-1.psd differ
diff --git a/filter/source/graphicfilter/ipsd/ipsd.cxx b/filter/source/graphicfilter/ipsd/ipsd.cxx
index 7fbd5ab..a5bea9f 100644
--- a/filter/source/graphicfilter/ipsd/ipsd.cxx
+++ b/filter/source/graphicfilter/ipsd/ipsd.cxx
@@ -172,9 +172,6 @@ bool PSDReader::ReadPSD(Graphic & rGraphic )
 
 bool PSDReader::ImplReadHeader()
 {
-    sal_uInt16  nCompression;
-    sal_uInt32  nColorLength, nResourceLength, nLayerMaskLength;
-
     mpFileHeader = new PSDFileHeader;
 
     m_rPSD.ReadUInt32( mpFileHeader->nSignature ).ReadUInt16( mpFileHeader->nVersion ).ReadUInt32( mpFileHeader->nPad1 ).        ReadUInt16( mpFileHeader->nPad2 ).ReadUInt16( mpFileHeader->nChannels ).ReadUInt32( mpFileHeader->nRows ).            ReadUInt32( mpFileHeader->nColumns ).ReadUInt16( mpFileHeader->nDepth ).ReadUInt16( mpFileHeader->nMode );
@@ -194,6 +191,7 @@ bool PSDReader::ImplReadHeader()
 
     mnDestBitDepth = ( nDepth == 16 ) ? 8 : nDepth;
 
+    sal_uInt32 nColorLength(0);
     m_rPSD.ReadUInt32( nColorLength );
     if ( mpFileHeader->nMode == PSD_CMYK )
     {
@@ -270,7 +268,10 @@ bool PSDReader::ImplReadHeader()
         default:
             return false;
     }
-    m_rPSD.ReadUInt32( nResourceLength );
+    sal_uInt32 nResourceLength(0);
+    m_rPSD.ReadUInt32(nResourceLength);
+    if (nResourceLength > m_rPSD.remainingSize())
+        return false;
     sal_uInt32 nLayerPos = m_rPSD.Tell() + nResourceLength;
 
     // this is a loop over the resource entries to get the resolution info
@@ -291,8 +292,8 @@ bool PSDReader::ImplReadHeader()
         if ( nResEntryLen & 1 )
             nResEntryLen++;             // the resource entries are padded
         sal_uInt32 nCurrentPos = m_rPSD.Tell();
-        if ( ( nResEntryLen + nCurrentPos ) > nLayerPos )   // check if size
-            break;                                          // is possible
+        if (nResEntryLen > (nLayerPos - nCurrentPos))   // check if size
+            break;                                      // is possible
         switch( nUniqueID )
         {
             case 0x3ed :    // UID for the resolution info
@@ -307,10 +308,12 @@ bool PSDReader::ImplReadHeader()
         m_rPSD.Seek( nCurrentPos + nResEntryLen );          // set the stream to the next
     }                                                       // resource entry
     m_rPSD.Seek( nLayerPos );
+    sal_uInt32 nLayerMaskLength(0);
     m_rPSD.ReadUInt32( nLayerMaskLength );
     m_rPSD.SeekRel( nLayerMaskLength );
 
-    m_rPSD.ReadUInt16( nCompression );
+    sal_uInt16 nCompression(0);
+    m_rPSD.ReadUInt16(nCompression);
     if ( nCompression == 0 )
     {
         mbCompression = false;
@@ -326,8 +329,6 @@ bool PSDReader::ImplReadHeader()
     return true;
 }
 
-
-
 bool PSDReader::ImplReadBody()
 {
     sal_uLong       nX, nY;
commit 313037a7ed10e979a3af8ffac801dd6b6bdb7615
Author: Julien Nabet <serval2412 at yahoo.fr>
Date:   Sun Sep 13 09:42:01 2015 +0200

    cppcheck: Mismatching allocation and deallocation
    
    + Typo: excecptionTypeSizeArray->exceptionTypeSizeArray
    
    Cherry-picked from 81d62c5f48f3bf341c4c7bdaef5a5ce5941f3e62
    
    Change-Id: I6fac3bea1eba094e87717d20a08ec7cf6151e2df
    Reviewed-on: https://gerrit.libreoffice.org/18527
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Noel Grandin <noelgrandin at gmail.com>

diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
index f95a045..321a168 100644
--- a/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
+++ b/bridges/source/cpp_uno/msvc_win32_x86-64/except.cxx
@@ -609,8 +609,8 @@ RaiseInfo::RaiseInfo(typelib_TypeDescription * pTD)throw ()
 
     // 2.Pass: Get the total needed memory for class ExceptionType
     // (with embedded type_info) and keep the sizes for each instance
-    // is stored in alloced int array
-    int *excecptionTypeSizeArray = new int[nLen];
+    // is stored in allocated int array
+    int *exceptionTypeSizeArray = new int[nLen];
 
     nLen = 0;
     for (pCompTD = (typelib_CompoundTypeDescription*)pTD;
@@ -625,14 +625,14 @@ RaiseInfo::RaiseInfo(typelib_TypeDescription * pTD)throw ()
             n++;
             typeInfoLen = n*4;
         }
-        excecptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
+        exceptionTypeSizeArray[nLen++] = typeInfoLen + sizeof(ExceptionType);
     }
 
     // Total ExceptionType related mem
     int excTypeAddLen = 0;
     for (int i = 0; i < nLen; i++)
     {
-        excTypeAddLen += excecptionTypeSizeArray[i];
+        excTypeAddLen += exceptionTypeSizeArray[i];
     }
 
     // Allocate mem for code and all dynamic data in one chunk to guarantee
@@ -684,7 +684,7 @@ RaiseInfo::RaiseInfo(typelib_TypeDescription * pTD)throw ()
         // Next trampoline entry offset
         pCodeOffset += codeSnippetSize;
         // Next ExceptionType placement offset
-        etMemOffset += excecptionTypeSizeArray[nPos - 1];
+        etMemOffset += exceptionTypeSizeArray[nPos - 1];
 
         // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
         types[nPos++]
@@ -694,7 +694,7 @@ RaiseInfo::RaiseInfo(typelib_TypeDescription * pTD)throw ()
     assert(etMem + etMemOffset == pCode + totalSize);
 
     // remove array
-    delete excecptionTypeSizeArray;
+    delete[] exceptionTypeSizeArray;
 }
 
 RaiseInfo::~RaiseInfo() throw ()
commit 00379a83cad8a016c54b3d90fef472a2ca6aeb96
Author: László Németh <laszlo.nemeth at collabora.com>
Date:   Fri Sep 11 17:20:29 2015 +0200

    tdf#92145: Writer table rows/columns can't be resized
    
    with disabled rulers. (This fix was suggested by Tomaž Vajngerl.)
    
    (Cherry-picked from the commit ed031895f6f5b361cccc6811b53c6f2b9cfc3e23)
    
    Conflicts:
    	svtools/source/control/ruler.cxx
    
    Change-Id: I161237cdb4941c0eaf934223b078acd94d72e21d
    Reviewed-on: https://gerrit.libreoffice.org/18507
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/svtools/source/control/ruler.cxx b/svtools/source/control/ruler.cxx
index d4b9374..2d4486c 100644
--- a/svtools/source/control/ruler.cxx
+++ b/svtools/source/control/ruler.cxx
@@ -2344,6 +2344,12 @@ bool Ruler::StartDocDrag( const MouseEvent& rMEvt, RulerType eDragType )
         // update ruler
         if ( mbFormat )
         {
+            if (!IsReallyVisible())
+            {
+                // set mpData for ImplDocHitTest()
+                ImplFormat(*this);
+            }
+
             Invalidate(INVALIDATE_NOERASE);
         }
 
commit ce80d8374938952a38e9fb2149ddae23b09a0b53
Author: Niklas Johansson <sleeping.pillow at gmail.com>
Date:   Sat Sep 12 09:10:35 2015 +0200

    Updated core
    Project: dictionaries  1a7a5f8de5e79e1f96095acf98bc5541a0cbac8f
    
    Update the Swedish spelling dictionary
    
    Change-Id: I5ae96f88587f5eeb0811290ab24bba28d3bc5013
    Reviewed-on: https://gerrit.libreoffice.org/18514
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/dictionaries b/dictionaries
index 71f54e9..1a7a5f8 160000
--- a/dictionaries
+++ b/dictionaries
@@ -1 +1 @@
-Subproject commit 71f54e95a0b443c673f924c71e23d04b540cc441
+Subproject commit 1a7a5f8de5e79e1f96095acf98bc5541a0cbac8f
commit e5544e485f8b82612a909568174b8ad142bed54e
Author: Michael Stahl <mstahl at redhat.com>
Date:   Wed Sep 9 10:30:04 2015 +0200

    tdf#92036: sw: fix idle spelling loop
    
    There is a sort of intentional infinite loop in the idle spell checking
    handler: while the user is typing a word, it should not be marked as
    invalid yet, in order not to annoy them with red underlines.
    
    So the word where the cursor is positioned always remained dirty, unless
    you happen to have a grammar checker enabled, which clears the
    paragraph's dirty flag from a separate thread.
    
    To avoid the infinite loop, add another spell checking state "PENDING"
    which is the same as dirty except that it should cancel the idle spell
    checking.
    
    The idle spell checking will run again when the user does the next
    editing operation.  Notably this means if the user just moves the cursor
    out of the wrongly spelled word, it won't be underlined yet, but that
    appears a minor issue, and checking when the cursor leaves the word
    appears too hard to implement.
    
    (cherry picked from commit 4c91e94e892943ef5e031d65f6f42864233cb4cd)
    
    Change-Id: Ifb3d6d17f94f9f1cfad82e70dfa79f1594c38647
    Reviewed-on: https://gerrit.libreoffice.org/18511
    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>

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 94ffd6a..87abad9 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -184,13 +184,16 @@ class SW_DLLPUBLIC SwTextNode: public SwContentNode, public ::sfx2::Metadatable
     void DelFrms_TextNodePart();
 
 public:
+    enum class WrongState { TODO, PENDING, DONE };
+
     bool IsWordCountDirty() const;
+    WrongState GetWrongDirty() const;
     bool IsWrongDirty() const;
     bool IsGrammarCheckDirty() const;
     bool IsSmartTagDirty() const;
     bool IsAutoCompleteWordDirty() const;
     void SetWordCountDirty( bool bNew ) const;
-    void SetWrongDirty( bool bNew ) const;
+    void SetWrongDirty(WrongState eNew) const;
     void SetGrammarCheckDirty( bool bNew ) const;
     void SetSmartTagDirty( bool bNew ) const;
     void SetAutoCompleteWordDirty( bool bNew ) const;
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index 2b82850..3d7497d 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -1100,14 +1100,14 @@ static bool lcl_SpellAndGrammarAgain( const SwNodePtr& rpNd, void* pArgs )
         {
             if( pTextNode->GetWrong() &&
                 pTextNode->GetWrong()->InvalidateWrong() )
-                pTextNode->SetWrongDirty( true );
+                pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
             if( pTextNode->GetGrammarCheck() &&
                 pTextNode->GetGrammarCheck()->InvalidateWrong() )
                 pTextNode->SetGrammarCheckDirty( true );
         }
         else
         {
-            pTextNode->SetWrongDirty( true );
+            pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
             if( pTextNode->GetWrong() )
                 pTextNode->GetWrong()->SetInvalid( 0, COMPLETE_STRING );
             pTextNode->SetGrammarCheckDirty( true );
diff --git a/sw/source/core/inc/wrong.hxx b/sw/source/core/inc/wrong.hxx
index 10a0309..cd9da5c 100644
--- a/sw/source/core/inc/wrong.hxx
+++ b/sw/source/core/inc/wrong.hxx
@@ -211,7 +211,8 @@ public:
     inline void Validate(){ nBeginInvalid = nEndInvalid = COMPLETE_STRING; }
     void Invalidate( sal_Int32 nBegin, sal_Int32 nEnd );
     bool InvalidateWrong();
-    bool Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
+    enum class FreshState { FRESH, CURSOR, NOTHING };
+    FreshState Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
             sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos );
     sal_uInt16 GetWrongPos( sal_Int32 nValue ) const;
 
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index d1c5cd4..3c61e30 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1931,7 +1931,8 @@ bool SwLayIdle::_DoIdleJob( const SwContentFrm *pCnt, IdleJobType eJob )
             case ONLINE_SPELLING :
             {
                 SwRect aRepaint( const_cast<SwTextFrm*>(static_cast<const SwTextFrm*>(pCnt))->_AutoSpell( pContentNode, nTextPos ) );
-                bPageValid = bPageValid && !pTextNode->IsWrongDirty();
+                // tdf#92036 PENDING should stop idle spell checking
+                bPageValid = bPageValid && (SwTextNode::WrongState::TODO != pTextNode->GetWrongDirty());
                 if( !bPageValid )
                     bAllValid = false;
                 if ( aRepaint.HasArea() )
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 886cec5..a4a707f 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -845,7 +845,7 @@ static void lcl_SetWrong( SwTextFrm& rFrm, sal_Int32 nPos, sal_Int32 nCnt, bool
             pTextNode->SetSmartTags( new SwWrongList( WRONGLIST_SMARTTAG ) );
             pTextNode->GetSmartTags()->SetInvalid( nPos, nEnd );
         }
-        pTextNode->SetWrongDirty( true );
+        pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
         pTextNode->SetGrammarCheckDirty( true );
         pTextNode->SetWordCountDirty( true );
         pTextNode->SetAutoCompleteWordDirty( true );
diff --git a/sw/source/core/text/wrong.cxx b/sw/source/core/text/wrong.cxx
index 0ea4c52..1fb87d9 100644
--- a/sw/source/core/text/wrong.cxx
+++ b/sw/source/core/text/wrong.cxx
@@ -356,11 +356,17 @@ void SwWrongList::Move( sal_Int32 nPos, sal_Int32 nDiff )
 
    @return <true> if ???
  */
-bool SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
-                             sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos )
+auto SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
+     sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos ) -> FreshState
 {
-    // length of word must be greater than 0 and cursor position must be outside the word
-    bool bRet = nLen && ( nCursorPos > nPos + nLen || nCursorPos < nPos );
+    // length of word must be greater than 0
+    // only report a spelling error if the cursor position is outside the word,
+    // so that the user is not annoyed while typing
+    FreshState eRet = (nLen)
+        ? (nCursorPos > nPos + nLen || nCursorPos < nPos)
+            ? FreshState::FRESH
+            : FreshState::CURSOR
+        : FreshState::NOTHING;
 
     sal_Int32 nWrPos = 0;
     sal_Int32 nWrEnd = rEnd;
@@ -383,11 +389,11 @@ bool SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
     if( nCnt < Count() && nWrPos == nPos && Len( nCnt ) == nLen )
     {
         ++nCnt;
-        bRet = true;
+        eRet = FreshState::FRESH;
     }
     else
     {
-        if( bRet )
+        if (FreshState::FRESH == eRet)
         {
             if( rStart > nPos )
                 rStart = nPos;
@@ -417,7 +423,7 @@ bool SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
 
     Remove( nIndex, nCnt - nIndex );
 
-    return bRet;
+    return eRet;
 }
 
 void SwWrongList::Invalidate( sal_Int32 nBegin, sal_Int32 nEnd )
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index a56d675..9606c12 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -424,7 +424,7 @@ SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
         {
             pNode->SetWrong( GetWrong()->SplitList( nSplitPos ) );
         }
-        SetWrongDirty( true );
+        SetWrongDirty(WrongState::TODO);
 
         if( GetGrammarCheck() )
         {
@@ -527,7 +527,7 @@ SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
     {
         SwWrongList *pList = GetWrong();
         SetWrong( 0, false );
-        SetWrongDirty( true );
+        SetWrongDirty(WrongState::TODO);
 
         SwGrammarMarkUp *pList3 = GetGrammarCheck();
         SetGrammarCheck( 0, false );
@@ -648,7 +648,7 @@ SwContentNode *SwTextNode::JoinNext()
         if( pList )
         {
             pList->JoinList( pTextNode->GetWrong(), nOldLen );
-            SetWrongDirty( true );
+            SetWrongDirty(WrongState::TODO);
             SetWrong( 0, false );
         }
         else
@@ -657,7 +657,7 @@ SwContentNode *SwTextNode::JoinNext()
             if( pList )
             {
                 pList->Move( 0, nOldLen );
-                SetWrongDirty( true );
+                SetWrongDirty(WrongState::TODO);
                 pTextNode->SetWrong( 0, false );
             }
         }
@@ -739,7 +739,7 @@ SwContentNode *SwTextNode::JoinPrev()
         if( pList )
         {
             pList->JoinList( GetWrong(), Len() );
-            SetWrongDirty( true );
+            SetWrongDirty(WrongState::TODO);
             pTextNode->SetWrong( 0, false );
             SetWrong( NULL );
         }
@@ -749,7 +749,7 @@ SwContentNode *SwTextNode::JoinPrev()
             if( pList )
             {
                 pList->Move( 0, nLen );
-                SetWrongDirty( true );
+                SetWrongDirty(WrongState::TODO);
                 SetWrong( 0, false );
             }
         }
@@ -1383,7 +1383,7 @@ const SwTextInputField* SwTextNode::GetOverlappingInputField( const SwTextAttr&
 void SwTextNode::DelFrms_TextNodePart()
 {
     SetWrong( NULL );
-    SetWrongDirty( true );
+    SetWrongDirty(WrongState::TODO);
 
     SetGrammarCheck( NULL );
     SetGrammarCheckDirty( true );
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 0c42a76..adcbf5c 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1311,6 +1311,7 @@ SwRect SwTextFrm::_AutoSpell( const SwContentNode* pActNode, sal_Int32 nActPos )
     }
 
     bool bFresh = nBegin < nEnd;
+    bool bPending(false);
 
     if( bFresh )
     {
@@ -1353,13 +1354,19 @@ SwRect SwTextFrm::_AutoSpell( const SwContentNode* pActNode, sal_Int32 nActPos )
                             pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
                             pNode->GetWrong()->SetInvalid( 0, nEnd );
                         }
-                        if( pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
-                            nBegin, nLen, nInsertPos, nActPos ) )
-                            pNode->GetWrong()->Insert( OUString(), 0, nBegin, nLen, nInsertPos++ );
-                        else
+                        SwWrongList::FreshState const eState(pNode->GetWrong()->Fresh(
+                            nChgStart, nChgEnd, nBegin, nLen, nInsertPos, nActPos));
+                        switch (eState)
                         {
-                            nInvStart = nBegin;
-                            nInvEnd = nBegin + nLen;
+                            case SwWrongList::FreshState::FRESH:
+                                pNode->GetWrong()->Insert(OUString(), 0, nBegin, nLen, nInsertPos++);
+                                break;
+                            case SwWrongList::FreshState::CURSOR:
+                                bPending = true; // fall-through to mark as invalid
+                            case SwWrongList::FreshState::NOTHING:
+                                nInvStart = nBegin;
+                                nInvEnd = nBegin + nLen;
+                                break;
                         }
                     }
                 }
@@ -1402,12 +1409,17 @@ SwRect SwTextFrm::_AutoSpell( const SwContentNode* pActNode, sal_Int32 nActPos )
         }
 
         pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
-        pNode->SetWrongDirty( COMPLETE_STRING != pNode->GetWrong()->GetBeginInv() );
+        pNode->SetWrongDirty(
+            (COMPLETE_STRING != pNode->GetWrong()->GetBeginInv())
+                ? ((bPending)
+                    ? SwTextNode::WrongState::PENDING
+                    : SwTextNode::WrongState::TODO)
+                : SwTextNode::WrongState::DONE);
         if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
             pNode->SetWrong( NULL );
     }
     else
-        pNode->SetWrongDirty( false );
+        pNode->SetWrongDirty(SwTextNode::WrongState::DONE);
 
     if( bAddAutoCmpl )
         pNode->SetAutoCompleteWordDirty( false );
@@ -2115,7 +2127,7 @@ struct SwParaIdleData_Impl
     sal_uLong nNumberOfChars;
     sal_uLong nNumberOfCharsExcludingSpaces;
     bool bWordCountDirty;
-    bool bWrongDirty;                   // Ist das Wrong-Feld auf invalid?
+    SwTextNode::WrongState eWrongDirty; ///< online spell checking needed/done?
     bool bGrammarCheckDirty;
     bool bSmartTagDirty;
     bool bAutoComplDirty;               // die ACompl-Liste muss angepasst werden
@@ -2129,7 +2141,7 @@ struct SwParaIdleData_Impl
         nNumberOfChars      ( 0 ),
         nNumberOfCharsExcludingSpaces ( 0 ),
         bWordCountDirty     ( true ),
-        bWrongDirty         ( true ),
+        eWrongDirty         ( SwTextNode::WrongState::TODO ),
         bGrammarCheckDirty  ( true ),
         bSmartTagDirty      ( true ),
         bAutoComplDirty     ( true ) {};
@@ -2276,17 +2288,22 @@ bool SwTextNode::IsWordCountDirty() const
     return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bWordCountDirty;
 }
 
-void SwTextNode::SetWrongDirty( bool bNew ) const
+void SwTextNode::SetWrongDirty(WrongState eNew) const
 {
     if ( m_pParaIdleData_Impl )
     {
-        m_pParaIdleData_Impl->bWrongDirty = bNew;
+        m_pParaIdleData_Impl->eWrongDirty = eNew;
     }
 }
 
+auto SwTextNode::GetWrongDirty() const -> WrongState
+{
+    return (m_pParaIdleData_Impl) ? m_pParaIdleData_Impl->eWrongDirty : WrongState::DONE;
+}
+
 bool SwTextNode::IsWrongDirty() const
 {
-    return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bWrongDirty;
+    return m_pParaIdleData_Impl && m_pParaIdleData_Impl->eWrongDirty != WrongState::DONE;
 }
 
 void SwTextNode::SetGrammarCheckDirty( bool bNew ) const
diff --git a/sw/source/core/unocore/unoflatpara.cxx b/sw/source/core/unocore/unoflatpara.cxx
index bec164a..8bda7b7 100644
--- a/sw/source/core/unocore/unoflatpara.cxx
+++ b/sw/source/core/unocore/unoflatpara.cxx
@@ -199,7 +199,10 @@ void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal ) t
     if (GetTextNode())
     {
         if ( text::TextMarkupType::SPELLCHECK == nType )
-            GetTextNode()->SetWrongDirty( !bVal );
+        {
+            GetTextNode()->SetWrongDirty(
+                (bVal) ? SwTextNode::WrongState::DONE : SwTextNode::WrongState::TODO);
+        }
         else if ( text::TextMarkupType::SMARTTAG == nType )
             GetTextNode()->SetSmartTagDirty( !bVal );
         else if( text::TextMarkupType::PROOFREADING == nType )
diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx
index 6de0271..e673fb0 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -2562,7 +2562,7 @@ throw (uno::RuntimeException, std::exception)
 
     if ( text::TextMarkupType::SPELLCHECK == nType )
     {
-        txtNode->SetWrongDirty(true);
+        txtNode->SetWrongDirty(SwTextNode::WrongState::TODO);
         txtNode->SetWrong(0, true);
     }
     else if( text::TextMarkupType::PROOFREADING == nType )
commit ddb9c7c40be9b902425600e018f3a55fa88417f2
Author: Michael Stahl <mstahl at redhat.com>
Date:   Fri Sep 11 17:20:27 2015 +0200

    Revert "Fix single node CopyRange"
    
    This reverts commit 9099e21b89184bd4e39def497e483cac4a77ec5a.
    
    It causes the problem that frames anchored to the same node where
    redlines start or end get duplicated during Hide.
    
    Jan-Marek said that the original mail-merge related problem this change
    was fixing is now most likely fixed differently, and the test in
    testMultiPageAnchoredDraws() still passes.
    
    (cherry picked from commit e84f0a9b3223f49b0829f2f55dacbf11ae201c1e)
    
    sw: add unit test for the redline frame duplication regression
    (cherry picked from commit d5ffcba07acb4dd5bd68373d40f07af825f07fba)
    
    Change-Id: Ie84fed3f64be7696782bc557004eb18fccc5b64b
    Reviewed-on: https://gerrit.libreoffice.org/18509
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/sw/inc/IDocumentContentOperations.hxx b/sw/inc/IDocumentContentOperations.hxx
index 91ca8ce..75b4f84 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -79,6 +79,9 @@ public:
         The position can be in the same or in an another document. It can also
         be within the range!
 
+        \warning The range has to include at least two nodes or has to be a
+        SwDoc::IsColumnSelection!
+
         Normally this function should work only with content nodes. But there
         is a special case used by SwDoc::Paste, which starts the SwPaM at the
         content start node. This position doesn't contain any content:
diff --git a/sw/qa/extras/uiwriter/data/redlineFrame.fodt b/sw/qa/extras/uiwriter/data/redlineFrame.fodt
new file mode 100644
index 0000000..31c5f50
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/redlineFrame.fodt
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oas
 is:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:
 experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:meta><meta:initial-creator>ms </meta:initial-creator><meta:creation-date>2015-08-24T21:49:45.305718699</meta:creation-date><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="0" meta:word-count="0" meta:character-count="0" meta:non-whitespace-character-count="0"/><meta:generator>LibreOfficeDev/4.3.7.2$Linux_X86_64 LibreOffice_project/8a35821d8636a03b8bf4e15b48f59794652c68ba</meta:generator></office:meta>
+ <office:font-face-decls>
+  <style:font-face style:name="Lohit Devanagari1" svg:font-family="'Lohit Devanagari'"/>
+  <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/>
+  <style:font-face style:name="Liberation Sans" svg:font-family="'Liberation Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>
+  <style:font-face style:name="Lohit Devanagari" svg:font-family="'Lohit Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/>
+  <style:font-face style:name="Source Han Sans CN Regular" svg:font-family="'Source Han Sans CN Regular'" style:font-family-generic="system" style:font-pitch="variable"/>
+ </office:font-face-decls>
+ <office:styles>
+  <style:default-style style:family="graphic">
+   <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
+   <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
+    <style:tab-stops/>
+   </style:paragraph-properties>
+   <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Sans CN Regular" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
+  </style:default-style>
+  <style:default-style style:family="paragraph">
+   <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
+   <style:text-properties style:use-window-font-color="true" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Source Han Sans CN Regular" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2"/>
+  </style:default-style>
+  <style:default-style style:family="table">
+   <style:table-properties table:border-model="collapsing"/>
+  </style:default-style>
+  <style:default-style style:family="table-row">
+   <style:table-row-properties fo:keep-together="auto"/>
+  </style:default-style>
+  <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
+ </office:styles>
+ <office:automatic-styles>
+  <style:page-layout style:name="pm1">
+   <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm">
+    <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+   </style:page-layout-properties>
+   <style:header-style/>
+   <style:footer-style/>
+  </style:page-layout>
+
+  <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
+    <style:text-properties officeooo:rsid="000b01fe" officeooo:paragraph-rsid="000b01fe"/>
+  </style:style>
+  <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard">
+    <style:text-properties officeooo:rsid="000b01fe" officeooo:paragraph-rsid="000b01fe"/>
+  </style:style>
+  <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Frame">
+    <style:graphic-properties style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph"/>
+  </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+  <style:master-page style:name="Standard" style:page-layout-name="pm1"/>
+ </office:master-styles>
+ <office:body>
+  <office:text>
+
+      <text:tracked-changes>
+        <text:changed-region xml:id="ct52929984" text:id="ct52929984">
+          <text:insertion>
+            <office:change-info>
+              <dc:creator>ms </dc:creator>
+              <dc:date>2015-09-10T15:36:00</dc:date>
+            </office:change-info>
+          </text:insertion>
+        </text:changed-region>
+        <text:changed-region xml:id="ct58510944" text:id="ct58510944">
+          <text:deletion>
+            <office:change-info>
+              <dc:creator>ms </dc:creator>
+              <dc:date>2015-09-10T15:36:00</dc:date>
+            </office:change-info>
+            <text:p text:style-name="P1"/>
+            <text:p text:style-name="P1">Removed text</text:p>
+          </text:deletion>
+        </text:changed-region>
+      </text:tracked-changes>
+      <text:p text:style-name="P1"><draw:frame draw:style-name="fr1" draw:name="Frame1" text:anchor-type="char" svg:width="2cm" draw:z-index="0"><draw:text-box fo:min-height="0.499cm"><text:p text:style-name="Frame_20_contents"/></draw:text-box></draw:frame><text:change-start text:change-id="ct52929984"/>Added text<text:change-end text:change-id="ct52929984"/><text:change text:change-id="ct58510944"/></text:p>
+
+  </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx
index 6b8b053..006cb46 100644
--- a/sw/qa/extras/uiwriter/uiwriter.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter.cxx
@@ -66,6 +66,7 @@ public:
     //Regression test of fdo#70143
     //EDITING: undo search&replace corrupt text when searching backward
     void testReplaceBackward();
+    void testRedlineFrame();
     void testFdo69893();
     void testFdo70807();
     void testImportRTF();
@@ -106,6 +107,7 @@ public:
     CPPUNIT_TEST_SUITE(SwUiWriterTest);
     CPPUNIT_TEST(testReplaceForward);
     CPPUNIT_TEST(testReplaceBackward);
+    CPPUNIT_TEST(testRedlineFrame);
     CPPUNIT_TEST(testFdo69893);
     CPPUNIT_TEST(testFdo70807);
     CPPUNIT_TEST(testImportRTF);
@@ -194,6 +196,31 @@ void SwUiWriterTest::testReplaceForward()
     CPPUNIT_ASSERT_EQUAL(ORIGINAL_REPLACE_CONTENT, pTextNode->GetText());
 }
 
+void SwUiWriterTest::testRedlineFrame()
+{
+    SwDoc * pDoc(createDoc("redlineFrame.fodt"));
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+    // there is exactly one frame
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount());
+
+    sal_uInt16 nMode = pWrtShell->GetRedlineMode();
+    CPPUNIT_ASSERT(nMode & nsRedlineMode_t::REDLINE_SHOW_DELETE);
+
+    // hide delete redlines
+    pWrtShell->SetRedlineMode(nMode & ~nsRedlineMode_t::REDLINE_SHOW_DELETE);
+
+    // there is still exactly one frame
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount());
+
+    pWrtShell->SetRedlineMode(nMode); // show again
+
+    // there is still exactly one frame
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xDrawPage->getCount());
+}
+
 void SwUiWriterTest::testFdo75110()
 {
     SwDoc* pDoc = createDoc("fdo75110.odt");
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index c6c69f3..1f387f4 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1584,7 +1584,7 @@ DocumentContentOperationsManager::CopyRange( SwPaM& rPam, SwPosition& rPos, cons
     bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
 
     // Catch if there's no copy to do
-    if( !rPam.HasMark() || ( *pStt > *pEnd && !bColumnSel ) )
+    if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) )
         return false;
 
     // Prevent copying in Flys that are anchored in the area
@@ -3132,8 +3132,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
     const SwPaM* pCopiedPaM,
     const bool bMakeNewFrms,
     const bool bDelRedlines,
-    const bool bCopyFlyAtFly,
-    const bool bMergedFirstNode ) const
+    const bool bCopyFlyAtFly ) const
 {
     SwDoc* pDest = rInsPos.GetNode().GetDoc();
 
@@ -3141,17 +3140,13 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
 
     SwNodeIndex aSavePos( rInsPos, -1 );
     bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
-    SwNodeRange aRg( rRg );
-    if ( bMergedFirstNode )
-        aRg.aStart++;
-    if ( aRg.aStart <= aRg.aEnd )
-        m_rDoc.GetNodes()._CopyNodes( aRg, rInsPos, bMakeNewFrms, true );
-    if ( !bMergedFirstNode )
-        ++aSavePos;
-    if ( bEndIsEqualEndPos )
+    m_rDoc.GetNodes()._CopyNodes( rRg, rInsPos, bMakeNewFrms, true );
+    ++aSavePos;
+    if( bEndIsEqualEndPos )
         const_cast<SwNodeIndex&>(rRg.aEnd) = aSavePos;
 
     aRedlRest.Restore();
+
 #if OSL_DEBUG_LEVEL > 0
     {
         //JP 17.06.99: Bug 66973 - check count only if the selection is in
@@ -3165,9 +3160,9 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
             !aTmpI.GetNode().IsEndNode() )
         {
             // If the range starts with a SwStartNode, it isn't copied
-            sal_uInt16 offset = (aRg.aStart.GetNode().GetNodeType() != ND_STARTNODE) ? 1 : 0;
+            sal_uInt16 offset = (rRg.aStart.GetNode().GetNodeType() != ND_STARTNODE) ? 1 : 0;
             OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() ==
-                    aRg.aEnd.GetIndex() - aRg.aStart.GetIndex() - 1 + offset,
+                    rRg.aEnd.GetIndex() - rRg.aStart.GetIndex() - 1 + offset,
                     "An insufficient number of nodes were copied!" );
         }
     }
@@ -3175,7 +3170,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
 
     {
         ::sw::UndoGuard const undoGuard(pDest->GetIDocumentUndoRedo());
-        CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly, bMergedFirstNode );
+        CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly );
     }
 
     SwNodeRange aCpyRange( aSavePos, rInsPos );
@@ -3201,8 +3196,7 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
     const SwNodeRange& rRg,
     const sal_Int32 nEndContentIndex,
     const SwNodeIndex& rStartIdx,
-    const bool bCopyFlyAtFly,
-    const bool bMergedFirstNode ) const
+    const bool bCopyFlyAtFly ) const
 {
     // First collect all Flys, sort them according to their ordering number,
     // and then only copy them. This maintains the ordering numbers (which are only
@@ -3335,8 +3329,6 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
 
                 ++aIdx;
             }
-            if ( bMergedFirstNode )
-                nAnchorTextNdNumInRange--;
 
             if ( !bAnchorTextNdFound )
             {
@@ -4105,7 +4097,7 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
     SwPosition* pEnd = rPam.End();
 
     // Catch when there's no copy to do.
-    if( !rPam.HasMark() || ( *pStt > *pEnd && !bColumnSel ) ||
+    if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) ||
         //JP 29.6.2001: 88963 - dont copy if inspos is in region of start to end
         //JP 15.11.2001: don't test inclusive the end, ever exclusive
         ( pDoc == &m_rDoc && *pStt <= rPos && rPos < *pEnd ))
@@ -4193,8 +4185,6 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
         pNumRuleToPropagate = 0;
     }
 
-    bool bHandledStartNode = false;
-
     // This do/while block is only there so that we can break out of it!
     do {
         if( pSttTextNd )
@@ -4202,8 +4192,6 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
             // Don't copy the beginning completely?
             if( !bCopyCollFormat || bColumnSel || pStt->nContent.GetIndex() )
             {
-                bHandledStartNode = true;
-
                 SwIndex aDestIdx( rPos.nContent );
                 bool bCopyOk = false;
                 if( !pDestTextNd )
@@ -4279,11 +4267,18 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
                         pEnd->nContent -= nCpyLen;
                 }
 
-                if( bCopyCollFormat && bOneNode )
+                if( bOneNode )
                 {
-                    pSttTextNd->CopyCollFormat( *pDestTextNd );
-                    POP_NUMRULE_STATE
+                    if (bCopyCollFormat)
+                    {
+                        pSttTextNd->CopyCollFormat( *pDestTextNd );
+                        POP_NUMRULE_STATE
+                    }
+
+                    break;
                 }
+
+                aRg.aStart++;
             }
         }
         else if( pDestTextNd )
@@ -4340,7 +4335,7 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
         }
 
         pDestTextNd = aInsPos.GetNode().GetTextNode();
-        if( pEndTextNd && (!bOneNode || !bHandledStartNode) )
+        if (pEndTextNd)
         {
             SwIndex aDestIdx( rPos.nContent );
             if( !pDestTextNd )
@@ -4384,7 +4379,7 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
         if( bCopyAll || aRg.aStart != aRg.aEnd )
         {
             SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange );
-            if( !bOneNode && pSttTextNd && bCopyCollFormat && pDestTextNd->HasSwAttrSet() )
+            if (pSttTextNd && bCopyCollFormat && pDestTextNd->HasSwAttrSet())
             {
                 aBrkSet.Put( *pDestTextNd->GetpSwAttrSet() );
                 if( SfxItemState::SET == aBrkSet.GetItemState( RES_BREAK, false ) )
@@ -4396,15 +4391,13 @@ bool DocumentContentOperationsManager::CopyImpl( SwPaM& rPam, SwPosition& rPos,
             if( aInsPos == pEnd->nNode )
             {
                 SwNodeIndex aSaveIdx( aInsPos, -1 );
-                CopyWithFlyInFly( aRg, 0, aInsPos, &rPam, bMakeNewFrms,
-                                  false, false, bHandledStartNode );
+                CopyWithFlyInFly( aRg, 0,aInsPos, &rPam, bMakeNewFrms, false );
                 ++aSaveIdx;
                 pEnd->nNode = aSaveIdx;
                 pEnd->nContent.Assign( aSaveIdx.GetNode().GetTextNode(), 0 );
             }
             else
-                CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, &rPam,
-                                  bMakeNewFrms, false, false, bHandledStartNode );
+                CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, &rPam, bMakeNewFrms, false );
 
             bCopyBookmarks = false;
 
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 3f60d4e..7a903af 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -896,6 +896,7 @@ SwNodeIndex SwDoc::AppendDoc(const SwDoc& rSource, sal_uInt16 const nStartPageNu
             SwPageDesc *const pTargetPageDesc, bool const bDeletePrevious, int pageOffset)
 {
     // GetEndOfExtras + 1 = StartOfContent == no content node!
+    // this ensures, that we have at least two nodes in the SwPaM.
     // @see IDocumentContentOperations::CopyRange
     SwNodeIndex aSourceIdx( rSource.GetNodes().GetEndOfExtras(), 1 );
     SwNodeIndex aSourceEndIdx( rSource.GetNodes().GetEndOfContent(), -1 );
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 24974d1..44560fc 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -106,13 +106,11 @@ public:
                             const SwPaM* pCopiedPaM = NULL,
                             bool bMakeNewFrms = true,
                             bool bDelRedlines = true,
-                            bool bCopyFlyAtFly = false,
-                            const bool bMergedFirstNode = false ) const;
+                            bool bCopyFlyAtFly = false ) const;
     void CopyFlyInFlyImpl(  const SwNodeRange& rRg,
                             const sal_Int32 nEndContentIndex,
                             const SwNodeIndex& rStartIdx,
-                            const bool bCopyFlyAtFly = false,
-                            const bool bMergedFirstNode = false ) const;
+                            const bool bCopyFlyAtFly = false ) const;
 
     /// Parameters for _Rst and lcl_SetTextFormatColl
     //originallyfrom docfmt.cxx
commit 58abf71db71628fdb1cb8e70e8aa55f3f790ce3c
Author: Lubosz Sarnecki <lubosz.sarnecki at collabora.co.uk>
Date:   Fri Sep 11 14:48:26 2015 +0200

    tdf#94031 - slideshow: bind correct GL context for prepareEnvironment
    
    Change-Id: Ib139e81f770531f7d808764dd3a77c7ac8d6fa3c
    Signed-off-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx
index f468f87..db50970 100644
--- a/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx
+++ b/slideshow/source/engine/OGLTrans/generic/OGLTrans_TransitionerImpl.cxx
@@ -1185,6 +1185,7 @@ void OGLTransitionerImpl::GLInitSlides()
     TimerContext aTimerContext("texture creation");
 #endif
 
+    mpContext->makeCurrent();
     prepareEnvironment();
 
     const OGLFormat* pFormat = NULL;
commit a023cd66e74a96aec52d891508cd757292513401
Author: Regina Henschel <rb.henschel at t-online.de>
Date:   Sat Aug 29 18:05:33 2015 +0200

    tdf#93634 repair getDisplayDirectory for Windows filepicker
    
    Change wrong PROP_FILENAME to correct PROP_DIRECTORY
    
    Change-Id: Iab2e16c486f487699e1574ed508539d95884bf9b
    Reviewed-on: https://gerrit.libreoffice.org/18127
    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 8775593bcc543b3d7021e20736f42fa13035870d)
    Reviewed-on: https://gerrit.libreoffice.org/18373

diff --git a/fpicker/source/win32/filepicker/VistaFilePicker.cxx b/fpicker/source/win32/filepicker/VistaFilePicker.cxx
index 4774857..4b2de9d 100644
--- a/fpicker/source/win32/filepicker/VistaFilePicker.cxx
+++ b/fpicker/source/win32/filepicker/VistaFilePicker.cxx
@@ -246,7 +246,7 @@ OUString SAL_CALL VistaFilePicker::getDisplayDirectory()
     RequestRef rRequest(new Request());
     rRequest->setRequest (VistaFilePickerImpl::E_GET_DIRECTORY);
     m_aAsyncExecute.triggerRequestThreadAware(rRequest, AsyncRequests::BLOCKED);
-    const OUString sDirectory = rRequest->getArgumentOrDefault(PROP_FILENAME, OUString());
+    const OUString sDirectory = rRequest->getArgumentOrDefault(PROP_DIRECTORY, OUString());
 
     return sDirectory;
 }
commit fa26aa0bdb0c93c2a3e5d0bfc879e9185a6e910e
Author: Eike Rathke <erack at redhat.com>
Date:   Thu Sep 10 15:52:21 2015 +0200

    Resolves: tdf#92995 do not delete caption objects that are held by Undo
    
    Drag&Drop Undo is a special case of ownership..
    
    Change-Id: I2fe7769c4d84efe09d432335d5d8e72d506bf7a1
    (cherry picked from commit 44f34c1163882c2e3086282374fee9cd55ee211f)
    Reviewed-on: https://gerrit.libreoffice.org/18470
    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>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 9d96793..fd27c10 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -583,7 +583,7 @@ public:
     ScPostIt* GetCellNote( SCROW nRow );
     const ScPostIt* GetCellNote( SCROW nRow ) const;
     const ScPostIt* GetCellNote( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const;
-    void DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 );
+    void DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership );
     bool HasCellNotes() const;
     void SetCellNote( SCROW nRow, ScPostIt* pNote);
     bool IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const;
diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx
index b95faf5..397808e 100644
--- a/sc/inc/global.hxx
+++ b/sc/inc/global.hxx
@@ -197,10 +197,11 @@ const InsertDeleteFlags IDF_OUTLINE   = InsertDeleteFlags::fromInt(0x0800);   //
 const InsertDeleteFlags IDF_NOCAPTIONS  = InsertDeleteFlags::fromInt(0x0200);   /// Internal use only (undo etc.): do not copy/delete caption objects of cell notes.
 const InsertDeleteFlags IDF_ADDNOTES    = InsertDeleteFlags::fromInt(0x0400);   /// Internal use only (copy from clip): do not delete existing cell contents when pasting notes.
 const InsertDeleteFlags IDF_SPECIAL_BOOLEAN  = InsertDeleteFlags::fromInt(0x1000);
+const InsertDeleteFlags IDF_FORGETCAPTIONS = InsertDeleteFlags::fromInt(0x2000); /// Internal use only (d&d undo): do not delete caption objects of cell notes.
 const InsertDeleteFlags IDF_ATTRIB     = IDF_HARDATTR | IDF_STYLES;
 const InsertDeleteFlags IDF_CONTENTS   = IDF_VALUE | IDF_DATETIME | IDF_STRING | IDF_NOTE | IDF_FORMULA | IDF_OUTLINE;
 const InsertDeleteFlags IDF_ALL        = IDF_CONTENTS | IDF_ATTRIB | IDF_OBJECTS;
-const InsertDeleteFlags IDF_ALL_USED_BITS = IDF_ALL | IDF_EDITATTR | IDF_NOCAPTIONS | IDF_ADDNOTES | IDF_SPECIAL_BOOLEAN;
+const InsertDeleteFlags IDF_ALL_USED_BITS = IDF_ALL | IDF_EDITATTR | IDF_NOCAPTIONS | IDF_ADDNOTES | IDF_SPECIAL_BOOLEAN | IDF_FORGETCAPTIONS;
 
 inline InsertDeleteFlags operator~ (const InsertDeleteFlags& rhs)
 {
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index bb6a37d..8929ecd 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1816,8 +1816,27 @@ void ScColumn::SetCellNote(SCROW nRow, ScPostIt* pNote)
     maCellNotes.set(nRow, pNote);
 }
 
-void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
+namespace {
+class ForgetCellNoteCaptionsHandler
+{
+
+public:
+    ForgetCellNoteCaptionsHandler() {}
+
+    void operator() ( size_t /*nRow*/, ScPostIt* p )
+    {
+        p->ForgetCaption();
+    }
+};
+}
+
+void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, bool bForgetCaptionOwnership )
 {
+    if (bForgetCaptionOwnership)
+    {
+        ForgetCellNoteCaptionsHandler aFunc;
+        sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
+    }
     rBlockPos.miCellNotePos =
         maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
 }
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 40ec240..757c3e3 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -684,7 +684,10 @@ void ScColumn::DeleteArea(
     }
 
     if (nDelFlag & IDF_NOTE)
-        DeleteCellNotes(aBlockPos, nStartRow, nEndRow);
+    {
+        bool bForgetCaptionOwnership = ((nDelFlag & IDF_FORGETCAPTIONS) != IDF_NONE);
+        DeleteCellNotes(aBlockPos, nStartRow, nEndRow, bForgetCaptionOwnership);
+    }
 
     if ( nDelFlag & IDF_EDITATTR )
     {
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 46b59c0..ac09eac 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -114,7 +114,7 @@ void ScColumn::DeleteBeforeCopyFromClip(
         }
 
         if (nDelFlag & IDF_NOTE)
-            DeleteCellNotes(aBlockPos, nRow1, nRow2);
+            DeleteCellNotes(aBlockPos, nRow1, nRow2, false);
 
         if (nDelFlag & IDF_EDITATTR)
             RemoveEditAttribs(nRow1, nRow2);
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index 2154466..9cecfa0 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -1239,7 +1239,14 @@ void ScUndoDragDrop::DoUndo( ScRange aRange )
     // do not undo objects and note captions, they are handled via drawing undo
     InsertDeleteFlags nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS;
 
-    rDoc.DeleteAreaTab( aRange, nUndoFlags );
+    // Additionally discard/forget caption ownership during deletion, as
+    // Drag&Drop is a special case in that the Undo holds captions of the
+    // transfered target range, which would get deleted and
+    // SdrGroupUndo::Undo() would attempt to access invalidated captions and
+    // crash, tdf#92995
+    InsertDeleteFlags nDelFlags = nUndoFlags | IDF_FORGETCAPTIONS;
+
+    rDoc.DeleteAreaTab( aRange, nDelFlags );
     pRefUndoDoc->CopyToDocument( aRange, nUndoFlags, false, &rDoc );
     if ( rDoc.HasAttrib( aRange, HASATTR_MERGED ) )
         rDoc.ExtendMerge( aRange, true );
commit 2d3dbdcd14dbca9e5827cb44e453cc45842dff14
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Sep 10 11:40:33 2015 +0200

    windows opengl: mpProgram seen as 0
    
    in JunitTest_sc_unoapi_3.
    
    Change-Id: Ic7e32979f31a3376b67eb3bef59373632461e39f
    (cherry picked from commit 0e682d47a792497211d33779312ca2cad9874ffb)
    Reviewed-on: https://gerrit.libreoffice.org/18490
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 10b5c35..85c3a3a 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -773,6 +773,12 @@ void OpenGLSalGraphicsImpl::DrawTrapezoid( const basegfx::B2DTrapezoid& trapezoi
         aVertices[j+1] = GLfloat(rPt.getY());
     }
 
+    if (!mpProgram)
+    {
+        SAL_WARN("vcl.opengl", "OpenGLSalGraphicsImpl::DrawTrapezoid: mpProgram is 0");
+        return;
+    }
+
     ApplyProgramMatrices();
     mpProgram->SetVertices( &aVertices[0] );
     glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints );
commit 1b381370b026f62397dc2d41ddcecf9d6523e044
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Mon Sep 7 08:42:46 2015 +0200

    tdf#83227 oox: reuse RelId in DML/VML export for the same graphic
    
    So that large images are written only once to the ZIP container when
    they are exported using both markups. This affects drawinglayer images,
    the Writer ones are handled directly in sw and were already
    deduplicated.
    
    (cherry picked from commit b484e9814c66d8d51cea974390963a6944bc9d73)
    
    Conflicts:
    	oox/source/export/drawingml.cxx
    
    Change-Id: Iff7c769329b42939833056b727b070f6a60da5e3
    Reviewed-on: https://gerrit.libreoffice.org/18491
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 3b9d847..fff1e2c 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -74,6 +74,10 @@ public:
     virtual void WriteOutliner(const OutlinerParaObject& rParaObj) = 0;
     /// Write the contents of the textbox that is associated to this shape.
     virtual void WriteTextBox(css::uno::Reference<css::drawing::XShape> xShape) = 0;
+    /// Look up the RelId of a graphic based on its checksum.
+    virtual OUString FindRelId(BitmapChecksum nChecksum) = 0;
+    /// Store the RelId of a graphic based on its checksum.
+    virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) = 0;
 protected:
     DMLTextExport() {}
     virtual ~DMLTextExport() {}
diff --git a/include/oox/export/vmlexport.hxx b/include/oox/export/vmlexport.hxx
index a87ed16..922b019 100644
--- a/include/oox/export/vmlexport.hxx
+++ b/include/oox/export/vmlexport.hxx
@@ -39,6 +39,10 @@ public:
     virtual oox::drawingml::DrawingML& GetDrawingML() = 0;
     /// Write the contents of the textbox that is associated to this shape in VML format.
     virtual void WriteVMLTextBox(css::uno::Reference<css::drawing::XShape> xShape) = 0;
+    /// Look up the RelId of a graphic based on its checksum.
+    virtual OUString FindRelId(BitmapChecksum nChecksum) = 0;
+    /// Store the RelId of a graphic based on its checksum.
+    virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) = 0;
 protected:
     VMLTextExport() {}
     virtual ~VMLTextExport() {}
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index da38474..878276a 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -769,7 +769,7 @@ void DrawingML::WriteOutline( Reference<XPropertySet> rXPropSet )
     mpFS->endElementNS( XML_a, XML_ln );
 }
 
-OUString DrawingML::WriteImage( const OUString& rURL, bool bRelPathToMedia )
+bool lcl_URLToGraphic(const OUString& rURL, Graphic& rGraphic)
 {
     OString aURLBS(OUStringToOString(rURL, RTL_TEXTENCODING_UTF8));
 
@@ -778,9 +778,18 @@ OUString DrawingML::WriteImage( const OUString& rURL, bool bRelPathToMedia )
 
     if ( index != -1 )
     {
-        DBG(fprintf (stderr, "begin: %ld %s\n", long( sizeof( aURLBegin ) ), USS( rURL ) + RTL_CONSTASCII_LENGTH( aURLBegin ) ));
-        Graphic aGraphic = GraphicObject( aURLBS.copy(RTL_CONSTASCII_LENGTH(aURLBegin)) ).GetTransformedGraphic ();
+        rGraphic = GraphicObject(aURLBS.copy(RTL_CONSTASCII_LENGTH(aURLBegin))).GetTransformedGraphic();
+        return true;
+    }
+
+    return false;
+}
 
+OUString DrawingML::WriteImage( const OUString& rURL, bool bRelPathToMedia )
+{
+    Graphic aGraphic;
+    if (lcl_URLToGraphic(rURL, aGraphic))
+    {
         return WriteImage( aGraphic , bRelPathToMedia );
     }
     else
@@ -930,7 +939,23 @@ OUString DrawingML::WriteImage( const Graphic& rGraphic , bool bRelPathToMedia )
 
 OUString DrawingML::WriteBlip( Reference< XPropertySet > rXPropSet, const OUString& rURL, bool bRelPathToMedia, const Graphic *pGraphic )
 {
-    OUString sRelId = pGraphic ? WriteImage( *pGraphic, bRelPathToMedia ) : WriteImage( rURL, bRelPathToMedia );
+    OUString sRelId;
+    BitmapChecksum nChecksum = 0;
+    if (!rURL.isEmpty() && mpTextExport)
+    {
+        Graphic aGraphic;
+        if (lcl_URLToGraphic(rURL, aGraphic))
+        {
+            nChecksum = aGraphic.GetChecksum();
+            sRelId = mpTextExport->FindRelId(nChecksum);
+        }
+    }
+    if (sRelId.isEmpty())
+    {
+        sRelId = pGraphic ? WriteImage( *pGraphic, bRelPathToMedia ) : WriteImage( rURL, bRelPathToMedia );
+        if (!rURL.isEmpty() && mpTextExport)
+            mpTextExport->CacheRelId(nChecksum, sRelId);
+    }
     sal_Int16 nBright = 0;
     sal_Int32 nContrast = 0;
 
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 7161a2f..d90ff82 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -583,7 +583,14 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect
                         aStream.Seek(0);
                         Graphic aGraphic;
                         GraphicConverter::Import(aStream, aGraphic);
-                        OUString aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
+
+                        BitmapChecksum nChecksum = aGraphic.GetChecksum();
+                        OUString aImageId = m_pTextExport->FindRelId(nChecksum);
+                        if (aImageId.isEmpty())
+                        {
+                            aImageId = m_pTextExport->GetDrawingML().WriteImage( aGraphic );
+                            m_pTextExport->CacheRelId(nChecksum, aImageId);
+                        }
                         pAttrList->add(FSNS(XML_r, XML_id), OUStringToOString(aImageId, RTL_TEXTENCODING_UTF8));
                         imageData = true;
                     }
diff --git a/sw/qa/extras/ooxmlexport/data/tdf83227.docx b/sw/qa/extras/ooxmlexport/data/tdf83227.docx
new file mode 100644
index 0000000..bca19a9
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf83227.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index 3727353..3a273f3 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -803,6 +803,18 @@ DECLARE_OOXMLEXPORT_TEST(testSimpleSdts, "simple-sdts.docx")
 
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf83227, "tdf83227.docx")
+{
+    // Bug document contains a rotated image, which is handled as a draw shape (not as a Writer image) on export.
+    if (!mbExported)
+        return;
+
+    uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL());
+    CPPUNIT_ASSERT_EQUAL(true, bool(xNameAccess->hasByName("word/media/image1.png")));
+    // This was also true, image was written twice.
+    CPPUNIT_ASSERT_EQUAL(false, bool(xNameAccess->hasByName("word/media/image2.png")));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 022ee0b..00aeb75 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -4074,6 +4074,22 @@ void DocxAttributeOutput::WriteSrcRect(const SdrObject* pSdrObj )
 void DocxAttributeOutput::ClearRelIdCache()
 {
     m_aRelIdCache.clear();
+    m_aSdrRelIdCache.clear();
+}
+
+OUString DocxAttributeOutput::FindRelId(BitmapChecksum nChecksum)
+{
+    OUString aRet;
+
+    if (m_aSdrRelIdCache.find(nChecksum) != m_aSdrRelIdCache.end())
+        aRet = m_aSdrRelIdCache[nChecksum];
+
+    return aRet;
+}
+
+void DocxAttributeOutput::CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId)
+{
+     m_aSdrRelIdCache[nChecksum] = rRelId;
 }
 
 void DocxAttributeOutput::FlyFrameGraphic( const SwGrfNode* pGrfNode, const Size& rSize, const SwFlyFrameFormat* pOLEFrameFormat, SwOLENode* pOLENode, const SdrObject* pSdrObj )
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index b7ce59d..4dbc29f 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -906,6 +906,8 @@ private:
 
     /// RelId <-> Graphic* cache, so that in case of alternate content, the same graphic only gets written once.
     std::map<const Graphic*, OString> m_aRelIdCache;
+    /// RelId <-> BitmapChecksum cache, similar to m_aRelIdCache, but used for non-Writer graphics, handled in oox.
+    std::map<BitmapChecksum, OUString> m_aSdrRelIdCache;
 
     /// members to control the existence of grabbagged SDT properties in the paragraph
     sal_Int32 m_nParagraphSdtPrToken;
@@ -963,6 +965,8 @@ public:
     virtual void WriteVMLTextBox(css::uno::Reference<css::drawing::XShape> xShape) SAL_OVERRIDE;
     /// DMLTextExport
     virtual void WriteTextBox(css::uno::Reference<css::drawing::XShape> xShape) SAL_OVERRIDE;
+    virtual OUString FindRelId(BitmapChecksum nChecksum) SAL_OVERRIDE;
+    virtual void CacheRelId(BitmapChecksum nChecksum, const OUString& rRelId) SAL_OVERRIDE;
     virtual oox::drawingml::DrawingML& GetDrawingML() SAL_OVERRIDE;
 
     void BulletDefinition(int nId, const Graphic& rGraphic, Size aSize) SAL_OVERRIDE;
commit b7ffafe77d95c72402bdac0328ca3bfcb7444067
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Sep 10 11:39:44 2015 +0200

    windows opengl: mpCurrentProgram seen as 0
    
    in JunitTest_sc_unoapi_3.
    
    Change-Id: Ibe12a31c1158f782bd7df115171b07e1843d025c
    (cherry picked from commit 57fc41adc9292f8980bb8bbbb0d7983310fe6fe3)
    Reviewed-on: https://gerrit.libreoffice.org/18489
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx
index d1df28b..ea9664e 100644
--- a/vcl/source/opengl/OpenGLContext.cxx
+++ b/vcl/source/opengl/OpenGLContext.cxx
@@ -1751,6 +1751,13 @@ OpenGLProgram* OpenGLContext::UseProgram( const OUString& rVertexShader, const O
         return pProgram;
 
     mpCurrentProgram = pProgram;
+
+    if (!mpCurrentProgram)
+    {
+        SAL_WARN("vcl.opengl", "OpenGLContext::UseProgram: mpCurrentProgram is 0");
+        return 0;
+    }
+
     mpCurrentProgram->Use();
 
     return mpCurrentProgram;
commit 8488315d565a061749546df27d2507d0927a8993
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Fri Sep 4 09:16:44 2015 +0200

    Related: tdf#92982 vcl rendercontext: optimize non-buffered paint of Cursor
    
    Change-Id: Ic8065d4f656d42f1e2e7d8b4c602010fa0ae2d34
    Reviewed-on: https://gerrit.libreoffice.org/18343
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>
    Tested-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/vcl/source/window/cursor.cxx b/vcl/source/window/cursor.cxx
index 1968a26..945789a 100644
--- a/vcl/source/window/cursor.cxx
+++ b/vcl/source/window/cursor.cxx
@@ -44,8 +44,11 @@ struct ImplCursorData
 static void ImplCursorInvert( ImplCursorData* pData )
 {
     vcl::Window* pWindow  = pData->mpWindow;
-    PaintBufferGuard aGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow);
-    vcl::RenderContext* pRenderContext = aGuard.GetRenderContext();
+    std::unique_ptr<PaintBufferGuard> pGuard;
+    const bool bDoubleBuffering = pWindow->SupportsDoubleBuffering();
+    if (bDoubleBuffering)
+        pGuard.reset(new PaintBufferGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow));
+    vcl::RenderContext* pRenderContext = bDoubleBuffering ? pGuard->GetRenderContext() : pWindow;
     Rectangle aPaintRect;
     bool    bMapMode = pRenderContext->IsMapModeEnabled();
     pRenderContext->EnableMapMode( false );
@@ -111,16 +114,19 @@ static void ImplCursorInvert( ImplCursorData* pData )
             if ( pData->mnOrientation )
                 aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
             pRenderContext->Invert( aPoly, nInvertStyle );
-            aPaintRect = aPoly.GetBoundRect();
+            if (bDoubleBuffering)
+                aPaintRect = aPoly.GetBoundRect();
         }
     }
     else
     {
         pRenderContext->Invert( aRect, nInvertStyle );
-        aPaintRect = aRect;
+        if (bDoubleBuffering)
+            aPaintRect = aRect;
     }
     pRenderContext->EnableMapMode( bMapMode );
-    aGuard.SetPaintRect(pRenderContext->PixelToLogic(aPaintRect));
+    if (bDoubleBuffering)
+        pGuard->SetPaintRect(pRenderContext->PixelToLogic(aPaintRect));
 }
 
 void vcl::Cursor::ImplDraw()
commit e576227d71788409110108281340005638f78bf1
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Thu Sep 10 17:25:27 2015 +0200

    windows opengl: make sure mpLastContext is indeed the current context
    
    There were two problems here:
    
    1) The OpenGLContext ctor registered the instance on the list of
    contexts, but platform-specific call (e.g. wglMakeCurrent()) was only
    made later. Add a registerAsCurrent() member function that helps
    ensuring that the last item in the context list is indeed the current
    context.
    
    2) OpenGLContext::prepareForYield() is called without the solar mutex
    being locked, but it still assumes that the last context in the context
    list is the thread's current context, which may not be true.  The result
    is that during JunitTest_sd_unoapi, we end up in a situation like:
    
    debug:4640:5240: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA65F8
    debug:4640:7944: OpenGLContext::registerAsCurrent: wglGetCurrentContext() is 000D0003, pSVData->maGDIData.mpLastContext is 00FA6C70
    debug:4640:5240: OpenGLContext::prepareForYield: start, wglGetCurrentContext() is 00010001, pSVData->maGDIData.mpLastContext is 00FA6C70
    
    I.e. one thread registers as current, an other registers as current, too (while

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list