[Libreoffice-commits] core.git: include/filter sw/qa sw/source

Luke Deller luke at deller.id.au
Sun Mar 23 05:58:18 PDT 2014


 include/filter/msfilter/sprmids.hxx  |    4 
 sw/qa/extras/ww8export/ww8export.cxx |    3 
 sw/source/filter/ww8/wrtww8.hxx      |    5 
 sw/source/filter/ww8/wrtww8gr.cxx    |   12 +
 sw/source/filter/ww8/ww8atr.cxx      |  118 ++++++++----------
 sw/source/filter/ww8/ww8par.hxx      |   22 +--
 sw/source/filter/ww8/ww8par2.cxx     |  182 +++++++++++----------------
 sw/source/filter/ww8/ww8par6.cxx     |  229 +++++++++++++++++------------------
 sw/source/filter/ww8/ww8scan.cxx     |  198 +++++++++++++++++-------------
 sw/source/filter/ww8/ww8struc.hxx    |  135 +++++++++++++++++---
 10 files changed, 501 insertions(+), 407 deletions(-)

New commits:
commit ad51d4952dc30e0d1cdcc6037556cd7c66a61542
Author: Luke Deller <luke at deller.id.au>
Date:   Wed Mar 5 23:30:39 2014 +1100

    Full colour borders in .doc import/export
    
    The BRC (BoRder Control) structure used in .doc files to specify border
    properties has undergone several revisions over time.  LibreOffice
    supports the WW6 and WW8 (Word '97) BRC versions, which allow the border
    colour to be selected from a palette of only 16 colours.
    
    This changeset adds support for the WW9 (Word 2000) BRC version, along
    with some new SPRMs (Single PRoperty Modifiers) which use it, so that
    border colours are preserved accurately in .doc import/export.
    
    This change covers:
    - page borders
    - paragraph borders
    - borders around a sequence of characters
    - table / table cell borders (import only)
    
    Further work is required to extend coverage to borders of pictures and
    export of borders in tables.
    
    The LO code was using the same class WW8_BRC to store the bits for either
    the WW6 or WW8 BRC.  This becomes a bit unmanagable when adding a third
    BRC version, so I have split this into a separate class for each version.
    
    Fixes fdo#68475, fdo#50185
    
    Change-Id: I7ebc15236497cbab9312d8659fe7ed0bee2c59ed
    Reviewed-on: https://gerrit.libreoffice.org/8646
    Tested-by: LibreOffice gerrit bot <gerrit at libreoffice.org>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.co.uk>

diff --git a/include/filter/msfilter/sprmids.hxx b/include/filter/msfilter/sprmids.hxx
index a760a64..adddee0 100644
--- a/include/filter/msfilter/sprmids.hxx
+++ b/include/filter/msfilter/sprmids.hxx
@@ -228,6 +228,10 @@ namespace NS_sprm {
     const sal_uInt16 LN_SBrcLeft = 0x702c;
     const sal_uInt16 LN_SBrcBottom = 0x702d;
     const sal_uInt16 LN_SBrcRight = 0x702e;
+    const sal_uInt16 LN_SBorderTop = 0xd234;
+    const sal_uInt16 LN_SBorderLeft = 0xd235;
+    const sal_uInt16 LN_SBorderBottom = 0xd236;
+    const sal_uInt16 LN_SBorderRight = 0xd237;
     const sal_uInt16 LN_SPgbProp = 0x522f;
     const sal_uInt16 LN_SDxtCharSpace = 0x7030;
     const sal_uInt16 LN_SDyaLinePitch = 0x9031;
diff --git a/sw/qa/extras/ww8export/ww8export.cxx b/sw/qa/extras/ww8export/ww8export.cxx
index 4c3a0ba..24b3c5a 100644
--- a/sw/qa/extras/ww8export/ww8export.cxx
+++ b/sw/qa/extras/ww8export/ww8export.cxx
@@ -121,8 +121,7 @@ DECLARE_WW8EXPORT_TEST(testCharacterBorder, "charborder.odt")
     // Border
     {
         const table::BorderLine2 aTopBorder = getProperty<table::BorderLine2>(xRun,"CharTopBorder");
-        // In the original ODT file the border color is 0xFF3333
-        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF0000,0,318,0,0,318), aTopBorder);
+        CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF3333,0,318,0,0,318), aTopBorder);
         CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder, getProperty<table::BorderLine2>(xRun,"CharLeftBorder"));
         CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder, getProperty<table::BorderLine2>(xRun,"CharBottomBorder"));
         CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder, getProperty<table::BorderLine2>(xRun,"CharRightBorder"));
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 883d1e3..21101e9c 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -1082,13 +1082,14 @@ public:
                                      const SwPageDesc* pNewPgDesc = 0 );
 
     void Out_BorderLine(ww::bytes& rO, const ::editeng::SvxBorderLine* pLine,
-        sal_uInt16 nDist, sal_uInt16 nSprmNo, bool bShadow);
+        sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9,
+        bool bShadow);
 
     void Out_SwFmtBox(const SvxBoxItem& rBox, bool bShadow);
     void Out_SwFmtTableBox( ww::bytes& rO, const SvxBoxItem * rBox );
     sal_uInt8 TransCol( const Color& rCol );
     bool TransBrush(const Color& rCol, WW8_SHD& rShd);
-    WW8_BRC TranslateBorderLine(const ::editeng::SvxBorderLine& pLine,
+    WW8_BRCVer9 TranslateBorderLine(const ::editeng::SvxBorderLine& pLine,
         sal_uInt16 nDist, bool bShadow);
 
     // #i77805# - new return value indicates, if an inherited outline numbering is suppressed
diff --git a/sw/source/filter/ww8/wrtww8gr.cxx b/sw/source/filter/ww8/wrtww8gr.cxx
index 7e59a05..a1c2d11 100644
--- a/sw/source/filter/ww8/wrtww8gr.cxx
+++ b/sw/source/filter/ww8/wrtww8gr.cxx
@@ -582,15 +582,18 @@ void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly,
                 WW8_BRC aBrc;
                 if (pLn)
                 {
-                    aBrc = rWrt.TranslateBorderLine( *pLn,
+                    WW8_BRCVer9 aBrc90 = rWrt.TranslateBorderLine( *pLn,
                         pBox->GetDistance( aLnArr[ i ] ), bShadow );
+                    sal_uInt8 ico = rWrt.TransCol(msfilter::util::BGRToRGB(
+                        aBrc90.cv()));
+                    aBrc = WW8_BRC(ico, aBrc90.dptLineWidth(), aBrc90.brcType(),
+                        aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
                 }
 
                 // use importer logic to determine how large the exported
                 // border will really be in word and adjust accordingly
                 short nSpacing;
-                short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
-                    &nSpacing);
+                short nThick = aBrc.DetermineBorderProperties(&nSpacing);
                 switch (aLnArr[ i ])
                 {
                     case BOX_LINE_TOP:
@@ -778,8 +781,7 @@ void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
         WW8_BRC aBrc;
 
         short nSpacing;
-        short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
-        &nSpacing);
+        short nThick = aBrc.DetermineBorderProperties(&nSpacing);
         switch (aLnArr[ i ])
         {
             case BOX_LINE_TOP:
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index ddb30bd..ea149f0 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -1229,7 +1229,7 @@ void WW8AttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden )
 
 void WW8AttributeOutput::CharBorder( const SvxBorderLine* pAllBorder, const sal_uInt16 /*nDist*/, const bool bShadow )
 {
-    m_rWW8Export.Out_BorderLine( *m_rWW8Export.pO, pAllBorder, 0, NS_sprm::LN_CBrc, bShadow );
+    m_rWW8Export.Out_BorderLine( *m_rWW8Export.pO, pAllBorder, 0, NS_sprm::LN_CBrc, NS_sprm::LN_CBorder, bShadow );
 }
 
 void WW8AttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline )
@@ -4169,16 +4169,16 @@ void WW8AttributeOutput::FormatFillGradient( const XFillGradientItem& /*rFillGra
 {
 }
 
-WW8_BRC WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
+WW8_BRCVer9 WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
     sal_uInt16 nDist, bool bShadow)
 {
     // M.M. This function writes out border lines to the word format similar to
     // what SwRTFWriter::OutRTFBorder does in the RTF filter Eventually it
     // would be nice if all this functionality was in the one place
-    WW8_BRC aBrc;
+    sal_uInt32 nColBGR = 0;
     sal_uInt16 nWidth = ::editeng::ConvertBorderWidthToWord(
             rLine.GetBorderLineStyle(), rLine.GetWidth());
-    sal_uInt8 brcType = 0, nColCode = 0;
+    sal_uInt8 brcType = 0;
 
     if( nWidth )                                // Linie ?
     {
@@ -4248,66 +4248,30 @@ WW8_BRC WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
             }
         }
 
-        // BRC.dxpLineWidth
+        // BRC.dptLineWidth
         if( bThick )
             nWidth /= 2;
 
-        if( bWrtWW8 )
-        {
-            // Angabe in 8tel Punkten, also durch 2.5, da 1 Punkt = 20 Twips
-            nWidth = (( nWidth * 8 ) + 10 ) / 20;
-            if( 0xff < nWidth )
-                nWidth = 0xff;
-        }
-        else
-        {
-            // Angabe in 0.75 pt
-            nWidth = ( nWidth + 7 ) / 15;
-            if( nWidth > 5 )
-                nWidth = 5;
-            ::editeng::SvxBorderStyle const eStyle(rLine.GetBorderLineStyle());
-            if (table::BorderLineStyle::DOTTED == eStyle)
-                nWidth = 6;
-            else if (table::BorderLineStyle::DASHED == eStyle)
-                nWidth = 7;
-        }
+        // convert width from twips (1/20 pt) to eighths of a point
+        nWidth = (( nWidth * 8 ) + 10 ) / 20;
+        if( 0xff < nWidth )
+            nWidth = 0xff;
 
         if( 0 == nWidth )                       // ganz duenne Linie
             nWidth = 1;                         //       nicht weglassen
 
-        // BRC.ico
-        nColCode = TransCol( rLine.GetColor() );
+        // BRC.cv
+        nColBGR = wwUtility::RGBToBGR(rLine.GetColor().GetRGBColor());
     }
 
-    // BRC.dxpSpace
+    // BRC.dptSpace
     sal_uInt16 nLDist = nDist;
     nLDist /= 20;               // Masseinheit : pt
     if( nLDist > 0x1f )
         nLDist = 0x1f;
 
-    if( bWrtWW8 )
-    {
-        aBrc.aBits1[0] = sal_uInt8(nWidth);
-        aBrc.aBits1[1] = brcType;
-        aBrc.aBits2[0] = nColCode;
-        aBrc.aBits2[1] = sal_uInt8(nLDist);
-
-        // fShadow, keine weiteren Einstellungen im WW moeglich
-        if( bShadow )
-            aBrc.aBits2[1] |= 0x20;
-    }
-    else
-    {
-        sal_uInt16 aBits = nWidth + ( brcType << 3 );
-        aBits |= (nColCode & 0x1f) << 6;
-        aBits |= nLDist << 11;
-        // fShadow, keine weiteren Einstellungen im WW moeglich
-        if( bShadow )
-            aBits |= 0x20;
-        ShortToSVBT16( aBits, aBrc.aBits1);
-    }
-
-    return aBrc;
+    return WW8_BRCVer9(nColBGR, sal_uInt8(nWidth), brcType, sal_uInt8(nLDist),
+        bShadow, false);
 }
 
 // MakeBorderLine() bekommt einen WW8Bytes* uebergeben, um die Funktion
@@ -4315,7 +4279,7 @@ WW8_BRC WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
 // Wenn nSprmNo == 0, dann wird der Opcode nicht ausgegeben.
 // bShadow darf bei Tabellenzellen *nicht* gesetzt sein !
 void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
-    sal_uInt16 nDist, sal_uInt16 nSprmNo, bool bShadow)
+    sal_uInt16 nDist, sal_uInt16 nSprmNo, sal_uInt16 nSprmNoVer9, bool bShadow)
 {
     OSL_ENSURE( ( nSprmNo == 0 ) ||
             ( nSprmNo >= 38 && nSprmNo <= 41 ) ||
@@ -4323,10 +4287,16 @@ void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
             ( nSprmNo >= NS_sprm::LN_SBrcTop && nSprmNo <= NS_sprm::LN_SBrcRight ),
             "Sprm for border out is of range" );
 
-    WW8_BRC aBrc;
+    WW8_BRCVer9 aBrcVer9;
+    WW8_BRC aBrcVer8;
 
-    if (pLine)
-        aBrc = TranslateBorderLine( *pLine, nDist, bShadow );
+    if( pLine && pLine->GetBorderLineStyle() != table::BorderLineStyle::NONE )
+    {
+        aBrcVer9 = TranslateBorderLine( *pLine, nDist, bShadow );
+        sal_uInt8 ico = TransCol( msfilter::util::BGRToRGB(aBrcVer9.cv()) );
+        aBrcVer8 = WW8_BRC( aBrcVer9.dptLineWidth(), aBrcVer9.brcType(), ico,
+            aBrcVer9.dptSpace(), aBrcVer9.fShadow(), aBrcVer9.fFrame() );
+    }
 
     if( bWrtWW8 )
     {
@@ -4334,15 +4304,22 @@ void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
         if ( nSprmNo != 0 )
             SwWW8Writer::InsUInt16( rO, nSprmNo );
 
-        rO.insert( rO.end(), aBrc.aBits1, aBrc.aBits1+2 );
-        rO.insert( rO.end(), aBrc.aBits2, aBrc.aBits2+2 );
+        rO.insert( rO.end(), aBrcVer8.aBits1, aBrcVer8.aBits2+2 );
+
+        if ( nSprmNoVer9 != 0 )
+        {
+            SwWW8Writer::InsUInt16( rO, nSprmNoVer9 );
+            rO.push_back(sizeof(WW8_BRCVer9));
+            rO.insert( rO.end(), aBrcVer9.aBits1, aBrcVer9.aBits2+4);
+        }
     }
     else
     {
+        WW8_BRCVer6 aBrcVer6(aBrcVer8);
         // WW95-SprmIds
         if ( nSprmNo != 0 )
             rO.push_back( static_cast<sal_uInt8>( nSprmNo ) );
-        rO.insert( rO.end(), aBrc.aBits1, aBrc.aBits1+2 );
+        rO.insert( rO.end(), aBrcVer6.aBits1, aBrcVer6.aBits1+2 );
     }
 }
 
@@ -4359,11 +4336,21 @@ void WW8Export::Out_SwFmtBox(const SvxBoxItem& rBox, bool bShadow)
     };
     static const sal_uInt16 aPBrc[] =
     {
-        NS_sprm::LN_PBrcTop, NS_sprm::LN_PBrcLeft, NS_sprm::LN_PBrcBottom, NS_sprm::LN_PBrcRight
+        // WW8 SPRMs
+        NS_sprm::LN_PBrcTop, NS_sprm::LN_PBrcLeft,
+        NS_sprm::LN_PBrcBottom, NS_sprm::LN_PBrcRight,
+        // WW9 SPRMs
+        NS_sprm::LN_PBorderTop, NS_sprm::LN_PBorderLeft,
+        NS_sprm::LN_PBorderBottom, NS_sprm::LN_PBorderRight
     };
     static const sal_uInt16 aSBrc[] =
     {
-        NS_sprm::LN_SBrcTop, NS_sprm::LN_SBrcLeft, NS_sprm::LN_SBrcBottom, NS_sprm::LN_SBrcRight
+        // WW8 SPRMs
+        NS_sprm::LN_SBrcTop, NS_sprm::LN_SBrcLeft,
+        NS_sprm::LN_SBrcBottom, NS_sprm::LN_SBrcRight,
+        // WW9 SPRMs
+        NS_sprm::LN_SBorderTop, NS_sprm::LN_SBorderLeft,
+        NS_sprm::LN_SBorderBottom, NS_sprm::LN_SBorderRight,
     };
     static const sal_uInt16 aWW6PBrc[] =
     {
@@ -4375,15 +4362,22 @@ void WW8Export::Out_SwFmtBox(const SvxBoxItem& rBox, bool bShadow)
     {
         const SvxBorderLine* pLn = rBox.GetLine( *pBrd );
 
-        sal_uInt16 nSprmNo = 0;
+        sal_uInt16 nSprmNo, nSprmNoVer9 = 0;
         if ( !bWrtWW8 )
             nSprmNo = aWW6PBrc[i];
         else if ( bOutPageDescs )
+        {
             nSprmNo = aSBrc[i];
+            nSprmNoVer9 = aSBrc[i+4];
+        }
         else
+        {
             nSprmNo = aPBrc[i];
+            nSprmNoVer9 = aPBrc[i+4];
+        }
 
-        Out_BorderLine( *pO, pLn, rBox.GetDistance( *pBrd ), nSprmNo, bShadow );
+        Out_BorderLine( *pO, pLn, rBox.GetDistance( *pBrd ), nSprmNo,
+            nSprmNoVer9, bShadow );
     }
 }
 
@@ -4411,7 +4405,7 @@ void WW8Export::Out_SwFmtTableBox( ww::bytes& rO, const SvxBoxItem * pBox )
         else
             pLn = & aBorderLine;
 
-        Out_BorderLine(rO, pLn, 0, 0, false);
+        Out_BorderLine(rO, pLn, 0, 0, 0, false);
     }
 }
 
diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx
index e25290c..a07f083 100644
--- a/sw/source/filter/ww8/ww8par.hxx
+++ b/sw/source/filter/ww8/ww8par.hxx
@@ -207,7 +207,7 @@ struct WW8FlyPara
     sal_Int16 nLeMgn, nRiMgn, nUpMgn, nLoMgn;           // Raender
     sal_uInt8 nSp29;                 // rohe Bindung + Alignment
     sal_uInt8 nSp37;                 // Wrap-Mode ( 1 / 2; 0 = no Apo ? )
-    WW8_BRC5 brc;               // Umrandung Top, Left, Bottom, Right, Between
+    WW8_BRCVer9_5 brc;          // Umrandung Top, Left, Bottom, Right, Between
     bool bBorderLines;          // Umrandungslinien
     bool bGrafApo;              // true: Dieser Rahmen dient allein dazu, die
                                 // enthaltene Grafik anders als zeichengebunden
@@ -758,7 +758,7 @@ class wwSection
 public:
     wwSection(const SwPosition &rPos);
     SEPr maSep;
-    WW8_BRC brc[4];
+    WW8_BRCVer9 brc[4];
     SwNodeIndex maStart;
     SwSection *mpSection;
     SwPageDesc *mpPage;
@@ -1006,7 +1006,7 @@ struct WW8TabBandDesc
     short nOverrideValues[MAX_COL + 1][4];
     WW8_SHD* pSHDs;
     sal_uInt32* pNewSHDs;
-    WW8_BRC aDefBrcs[6];
+    WW8_BRCVer9 aDefBrcs[6];
 
     bool bExist[MAX_COL];           // does this cell exist ?
     sal_uInt8 nTransCell[MAX_COL + 2];  // translation WW-Index -> SW-Index
@@ -1022,8 +1022,8 @@ struct WW8TabBandDesc
     static void setcelldefaults(WW8_TCell *pCells, short nCells);
     void ReadDef(bool bVer67, const sal_uInt8* pS);
     void ProcessDirection(const sal_uInt8* pParams);
-    void ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC);
-    void ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams);
+    void ProcessSprmTSetBRC(int nBrcVer, const sal_uInt8* pParamsTSetBRC);
+    void ProcessSprmTTableBorders(int nBrcVer, const sal_uInt8* pParams);
     void ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol);
     void ProcessSprmTDelete(const sal_uInt8* pParamsTDelete);
     void ProcessSprmTInsert(const sal_uInt8* pParamsTInsert);
@@ -1426,7 +1426,7 @@ private:
     const SfxPoolItem* GetFmtAttr( sal_uInt16 nWhich );
     bool JoinNode(SwPaM &rPam, bool bStealAttr = false);
 
-    bool IsBorder(const WW8_BRC* pbrc, bool bChkBtwn = false) const;
+    bool IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false) const;
 
     //Set closest writer border equivalent into rBox from pbrc, optionally
     //recording true winword dimensions in pSizeArray. nSetBorders to mark a
@@ -1436,14 +1436,14 @@ private:
 
     // Note #i20672# we can't properly support between lines so best to ignore
     // them for now
-    bool SetBorder(SvxBoxItem& rBox, const WW8_BRC* pbrc, short *pSizeArray=0,
-        sal_uInt8 nSetBorders=0xFF) const;
-    void GetBorderDistance(const WW8_BRC* pbrc, Rectangle& rInnerDist) const;
+    bool SetBorder(SvxBoxItem& rBox, const WW8_BRCVer9* pbrc,
+        short *pSizeArray=0, sal_uInt8 nSetBorders=0xFF) const;
+    void GetBorderDistance(const WW8_BRCVer9* pbrc, Rectangle& rInnerDist) const;
     sal_uInt16 GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing);
     bool SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
-    const WW8_BRC& aRightBrc) const;
+        const WW8_BRCVer9& aRightBrc) const;
     //returns true is a shadow was set
-    bool SetFlyBordersShadow(SfxItemSet& rFlySet, const WW8_BRC *pbrc,
+    bool SetFlyBordersShadow(SfxItemSet& rFlySet, const WW8_BRCVer9 *pbrc,
         short *SizeArray=0) const;
     void SetPageBorder(SwFrmFmt &rFmt, const wwSection &rSection) const;
 
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index 9209ea3..ca7cdc2 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -1128,21 +1128,21 @@ void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
                     sal_uInt8 aBits1 = pTc->aBits1Ver6;
                     pAktTC->bFirstMerged    = ( ( aBits1 & 0x01 ) != 0 );
                     pAktTC->bMerged     = ( ( aBits1 & 0x02 ) != 0 );
-                    memcpy( pAktTC->rgbrc[ WW8_TOP      ].aBits1,
-                                    pTc->rgbrcVer6[ WW8_TOP     ].aBits1, sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_LEFT     ].aBits1,
-                                    pTc->rgbrcVer6[ WW8_LEFT    ].aBits1, sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_BOT      ].aBits1,
-                                    pTc->rgbrcVer6[ WW8_BOT     ].aBits1, sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_RIGHT    ].aBits1,
-                                    pTc->rgbrcVer6[ WW8_RIGHT   ].aBits1, sizeof( SVBT16 ) );
+                    pAktTC->rgbrc[ WW8_TOP ]
+                        = WW8_BRC( pTc->rgbrcVer6[ WW8_TOP ] );
+                    pAktTC->rgbrc[ WW8_LEFT ]
+                        = WW8_BRC( pTc->rgbrcVer6[ WW8_LEFT ] );
+                    pAktTC->rgbrc[ WW8_BOT ]
+                        = WW8_BRC( pTc->rgbrcVer6[ WW8_BOT ] );
+                    pAktTC->rgbrc[ WW8_RIGHT ]
+                        = WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] );
                     if(    ( pAktTC->bMerged )
                             && ( i > 0             ) )
                     {
                         // Cell merged -> remember
                         //bWWMergedVer6[i] = true;
-                        memcpy( pTCs[i-1].rgbrc[ WW8_RIGHT ].aBits1,
-                                pTc->rgbrcVer6[  WW8_RIGHT ].aBits1, sizeof( SVBT16 ) );
+                        pTCs[i-1].rgbrc[ WW8_RIGHT ]
+                            = WW8_BRC( pTc->rgbrcVer6[ WW8_RIGHT ] );
                             // apply right border to previous cell
                             // bExist must not be set to false, because WW
                             // does not count this cells in text boxes....
@@ -1167,8 +1167,10 @@ void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
                 // note: in aBits1 there are 7 bits unused,
                 //       followed by another 16 unused bits
 
-                // In Version 8 koennen we can copy all border codes at once!
-                memcpy( pAktTC->rgbrc, pTc->rgbrcVer8, 4 * sizeof( WW8_BRC ) );
+                pAktTC->rgbrc[ WW8_TOP   ] = pTc->rgbrcVer8[ WW8_TOP   ];
+                pAktTC->rgbrc[ WW8_LEFT  ] = pTc->rgbrcVer8[ WW8_LEFT  ];
+                pAktTC->rgbrc[ WW8_BOT   ] = pTc->rgbrcVer8[ WW8_BOT   ];
+                pAktTC->rgbrc[ WW8_RIGHT ] = pTc->rgbrcVer8[ WW8_RIGHT ];
             }
         }
 
@@ -1191,7 +1193,7 @@ void WW8TabBandDesc::ReadDef(bool bVer67, const sal_uInt8* pS)
     }
 }
 
-void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSetBRC)
+void WW8TabBandDesc::ProcessSprmTSetBRC(int nBrcVer, const sal_uInt8* pParamsTSetBRC)
 {
     if( pParamsTSetBRC && pTCs ) // set one or more cell border(s)
     {
@@ -1211,98 +1213,43 @@ void WW8TabBandDesc::ProcessSprmTSetBRC(bool bVer67, const sal_uInt8* pParamsTSe
         bool bChangeTop    = (nFlag & 0x01) ? true : false;
 
         WW8_TCell* pAktTC  = pTCs + nitcFirst;
-        if( bVer67 )
-        {
-            WW8_BRCVer6* pBRC = (WW8_BRCVer6*)(pParamsTSetBRC+3);
-
-            for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
-            {
-                if( bChangeTop )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_TOP  ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeLeft )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeBottom )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_BOT  ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeRight )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                }
-            }
-        }
+        WW8_BRCVer9 brcVer9;
+        if( nBrcVer == 6 )
+            brcVer9 = WW8_BRC(*(WW8_BRCVer6*)(pParamsTSetBRC+3));
+        else if( nBrcVer == 8 )
+            brcVer9 = *(WW8_BRC*)(pParamsTSetBRC+3);
         else
-        {
-            WW8_BRC* pBRC = (WW8_BRC*)(pParamsTSetBRC+3);
+            brcVer9 = *(WW8_BRCVer9*)(pParamsTSetBRC+3);
 
-            for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
-            {
-                if( bChangeTop )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_TOP  ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_TOP  ].aBits2,
-                            pBRC->aBits2,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeLeft )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_LEFT ].aBits2,
-                            pBRC->aBits2,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeBottom )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_BOT  ].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_BOT  ].aBits2,
-                            pBRC->aBits2,
-                            sizeof( SVBT16 ) );
-                }
-                if( bChangeRight )
-                {
-                    memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits1,
-                            pBRC->aBits1,
-                            sizeof( SVBT16 ) );
-                    memcpy( pAktTC->rgbrc[ WW8_RIGHT].aBits2,
-                            pBRC->aBits2,
-                            sizeof( SVBT16 ) );
-                }
-            }
+        for( int i = nitcFirst; i < nitcLim; ++i, ++pAktTC )
+        {
+            if( bChangeTop )
+                pAktTC->rgbrc[ WW8_TOP   ] = brcVer9;
+            if( bChangeLeft )
+                pAktTC->rgbrc[ WW8_LEFT  ] = brcVer9;
+            if( bChangeBottom )
+                pAktTC->rgbrc[ WW8_BOT   ] = brcVer9;
+            if( bChangeRight )
+                pAktTC->rgbrc[ WW8_RIGHT ] = brcVer9;
         }
     }
 }
 
-void WW8TabBandDesc::ProcessSprmTTableBorders(bool bVer67, const sal_uInt8* pParams)
+void WW8TabBandDesc::ProcessSprmTTableBorders(int nBrcVer, const sal_uInt8* pParams)
 {
     // sprmTTableBorders
-    if( bVer67 )
+    if( nBrcVer == 6 )
     {
         for( int i = 0; i < 6; ++i )
-        {
-            aDefBrcs[i].aBits1[0] = pParams[   2*i ];
-            aDefBrcs[i].aBits1[1] = pParams[ 1+2*i ];
-        }
+            aDefBrcs[i] = WW8_BRC( ((WW8_BRCVer6*)&pParams)[i] );
+    }
+    else if ( nBrcVer == 8 )
+    {
+        for( int i = 0; i < 6; ++i )
+            aDefBrcs[i] = ((WW8_BRC*)&pParams)[i];
     }
-    else // aDefBrcs = *(BRC(*)[6])pS;
-        memcpy( aDefBrcs, pParams, 24 );
+    else
+        memcpy( aDefBrcs, pParams, sizeof( aDefBrcs ) );
 }
 
 void WW8TabBandDesc::ProcessSprmTDxaCol(const sal_uInt8* pParamsTDxaCol)
@@ -1606,8 +1553,8 @@ enum wwTableSprm
 
     sprmTTableWidth,sprmTTextFlow, sprmTFCantSplit, sprmTFCantSplit90,sprmTJc, sprmTFBiDi, sprmTDefTable,
     sprmTDyaRowHeight, sprmTDefTableShd, sprmTDxaLeft, sprmTSetBrc,
-    sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
-    sprmTDxaGapHalf, sprmTTableBorders,
+    sprmTSetBrc90, sprmTDxaCol, sprmTInsert, sprmTDelete, sprmTTableHeader,
+    sprmTDxaGapHalf, sprmTTableBorders, sprmTTableBorders90,
 
     sprmTDefTableNewShd, sprmTSpacing, sprmTNewSpacing
 };
@@ -1653,8 +1600,12 @@ wwTableSprm GetTableSprm(sal_uInt16 nId, ww::WordVersion eVer)
                     return sprmTDefTableShd;
                 case 0xD612:
                     return sprmTDefTableNewShd;
+                case 0xD613:
+                    return sprmTTableBorders90;
                 case 0xD620:
                     return sprmTSetBrc;
+                case 0xD62F:
+                    return sprmTSetBrc90;
                 case 0xD632:
                     return sprmTSpacing;
                 case 0xD634:
@@ -1782,6 +1733,9 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
         bool bTabRowJustRead   = false;
         const sal_uInt8* pShadeSprm = 0;
         const sal_uInt8* pNewShadeSprm = 0;
+        const sal_uInt8* pTableBorders = 0;
+        const sal_uInt8* pTableBorders90 = 0;
+        std::vector<const sal_uInt8*> aTSetBrcs, aTSetBrc90s;
         WW8_TablePos *pTabPos  = 0;
 
         // search end of a tab row
@@ -1828,7 +1782,10 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
                         bClaimLineFmt = true;
                         break;
                     case sprmTTableBorders:
-                        pNewBand->ProcessSprmTTableBorders(bOldVer, pParams);
+                        pTableBorders = pParams; // process at end
+                        break;
+                    case sprmTTableBorders90:
+                        pTableBorders90 = pParams; // process at end
                         break;
                     case sprmTTableHeader:
                         if (!bRepeatedSprm)
@@ -1875,7 +1832,10 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
                         }
                         break;
                     case sprmTSetBrc:
-                        pNewBand->ProcessSprmTSetBRC(bOldVer, pParams);
+                        aTSetBrcs.push_back(pParams); // process at end
+                        break;
+                    case sprmTSetBrc90:
+                        aTSetBrc90s.push_back(pParams); // process at end
                         break;
                     case sprmTDxaCol:
                         pNewBand->ProcessSprmTDxaCol(pParams);
@@ -1912,10 +1872,22 @@ WW8TabDesc::WW8TabDesc(SwWW8ImplReader* pIoClass, WW8_CP nStartCp) :
 
         if (bTabRowJustRead)
         {
+            // Some SPRMs need to be processed *after* ReadDef is called
+            // so they were saved up until here
             if (pShadeSprm)
                 pNewBand->ReadShd(pShadeSprm);
             if (pNewShadeSprm)
                 pNewBand->ReadNewShd(pNewShadeSprm, bOldVer);
+            if (pTableBorders90)
+                pNewBand->ProcessSprmTTableBorders(9, pTableBorders90);
+            else if (pTableBorders)
+                pNewBand->ProcessSprmTTableBorders(bOldVer ? 6 : 8,
+                    pTableBorders);
+            std::vector<const sal_uInt8*>::const_iterator iter;
+            for (iter = aTSetBrcs.begin(); iter != aTSetBrcs.end(); ++iter)
+                pNewBand->ProcessSprmTSetBRC(bOldVer ? 6 : 8, *iter);
+            for (iter = aTSetBrc90s.begin(); iter != aTSetBrc90s.end(); ++iter)
+                pNewBand->ProcessSprmTSetBRC(9, *iter);
         }
 
         if( nTabeDxaNew < SHRT_MAX )
@@ -2150,7 +2122,7 @@ void WW8TabDesc::CalcDefaults()
             int i, j;
             for( i = 0; i < 4; i ++ )
             {
-                if (pT->rgbrc[i].IsZeroed(pIo->bVer67))
+                if (pT->rgbrc[i].brcType()==0)
                 {
                     // if shadow is set, its invalid
                     j = i;
@@ -2189,12 +2161,10 @@ void WW8TabDesc::CalcDefaults()
             dimensions, so in that case increase the table to include the
             extra width of the right margin.
             */
-            if ( pIo->bVer67 ?
-             !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits1) & 0x20)
-           : !(SVBT16ToShort(pR->pTCs[pR->nWwCols-1].rgbrc[3].aBits2) & 0x2000))
+            if ( ! pR->pTCs[pR->nWwCols-1].rgbrc[3].fShadow() )
             {
                 short nThickness = pR->pTCs[pR->nWwCols-1].rgbrc[3].
-                    DetermineBorderProperties(pIo->bVer67);
+                    DetermineBorderProperties();
                 pR->nCenter[pR->nWwCols] = pR->nCenter[pR->nWwCols] + nThickness;
                 if (nThickness > nRightMaxThickness)
                     nRightMaxThickness = nThickness;
@@ -2207,12 +2177,10 @@ void WW8TabDesc::CalcDefaults()
             half is placed to the left of the nominal left side, and
             half to the right.
             */
-            if ( pIo->bVer67 ?
-                  !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits1) & 0x20)
-                : !(SVBT16ToShort(pR->pTCs[0].rgbrc[1].aBits2) & 0x2000))
+            if ( ! pR->pTCs[0].rgbrc[1].fShadow() )
             {
                 short nThickness = pR->pTCs[0].rgbrc[1].
-                    DetermineBorderProperties(pIo->bVer67);
+                    DetermineBorderProperties();
                 if (nThickness > nLeftMaxThickness)
                     nLeftMaxThickness = nThickness;
             }
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
index e8bb5e4..4923053 100644
--- a/sw/source/filter/ww8/ww8par6.cxx
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -109,7 +109,8 @@ using namespace nsHdFtFlags;
 #define MM_250 1417             // WW-Default fuer Hor. Seitenraender: 2.5 cm
 #define MM_200 1134             // WW-Default fuer u.Seitenrand: 2.0 cm
 
-static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRC* brc, WW8PLCFx_Cp_FKP* pPap,
+
+static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
     const WW8RStyle* pSty = 0, const WW8PLCFx_SEPX* pSep = 0);
 
 ColorData SwWW8ImplReader::GetCol(sal_uInt8 nIco)
@@ -1191,20 +1192,26 @@ void SwWW8ImplReader::CopyPageDescHdFt(const SwPageDesc* pOrgPageDesc,
 
 //   Hilfsroutinen fuer Grafiken und Apos und Tabellen
 
-static bool _SetWW8_BRC(bool bVer67, WW8_BRC& rVar, const sal_uInt8* pS)
+// Read BoRder Control structure
+// nBrcVer should be set to the version of the BRC record being read (6, 8 or 9)
+// This will be converted to the latest format (9).
+static bool _SetWW8_BRC(int nBrcVer, WW8_BRCVer9& rVar, const sal_uInt8* pS)
 {
+
     if( pS )
     {
-        if( bVer67 )
-            memcpy( rVar.aBits1, pS, sizeof( SVBT16 ) );
-        else
-            rVar = *((WW8_BRC*)pS);
+        if ( nBrcVer == 9 )
+            rVar = *(const WW8_BRCVer9*)pS;
+        else if( nBrcVer == 8 )
+            rVar = *(const WW8_BRC*)pS;
+        else // nBrcVer == 6
+            rVar = WW8_BRC(*(const WW8_BRCVer6*)pS);
     }
 
     return 0 != pS;
 }
 
-static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRC* brc, WW8PLCFx_Cp_FKP* pPap,
+static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
     const WW8RStyle* pSty, const WW8PLCFx_SEPX* pSep)
 {
 
@@ -1223,7 +1230,7 @@ static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRC* brc, WW8PLCFx_Cp_FKP* pPa
                                     pSprm[0], pSprm[1], pSprm[2], pSprm[3] ) )
              {
                 for( int i = 0; i < 4; ++i )
-                    nBorder |= int(_SetWW8_BRC( bVer67, brc[ i ], pSprm[ i ] ))<<i;
+                    nBorder |= int(_SetWW8_BRC( 8, brc[ i ], pSprm[ i ] ))<<i;
              }
         }
     }
@@ -1235,17 +1242,40 @@ static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRC* brc, WW8PLCFx_Cp_FKP* pPa
         static const sal_uInt16 aVer8Ids[5] =
                 { 0x6424, 0x6425, 0x6426, 0x6427, 0x6428 };
 
-        const sal_uInt16* pIds = bVer67 ? aVer67Ids : aVer8Ids;
+        static const sal_uInt16 aVer9Ids[5] =
+                { 0xC64E, 0xC64F, 0xC650, 0xC651, 0xC652 };
 
         if( pPap )
         {
-            for( int i = 0; i < 5; ++i, ++pIds )
-                nBorder |= int(_SetWW8_BRC( bVer67, brc[ i ], pPap->HasSprm( *pIds )))<<i;
+            if (bVer67)
+            {
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 6 , brc[ i ], pPap->HasSprm( aVer67Ids[ i ] )))<<i;
+            }
+            else
+            {
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 8 , brc[ i ], pPap->HasSprm( aVer8Ids[ i ] )))<<i;
+                // Version 9 BRCs if present will override version 8
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 9 , brc[ i ], pPap->HasSprm( aVer9Ids[ i ] )))<<i;
+            }
         }
         else if( pSty )
         {
-            for( int i = 0; i < 5; ++i, ++pIds )
-                nBorder |= int(_SetWW8_BRC( bVer67, brc[ i ], pSty->HasParaSprm( *pIds )))<<i;
+            if (bVer67)
+            {
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 6 , brc[ i ], pSty->HasParaSprm( aVer67Ids[ i ] )))<<i;
+            }
+            else
+            {
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 8 , brc[ i ], pSty->HasParaSprm( aVer8Ids[ i ] )))<<i;
+                // Version 9 BRCs if present will override version 8
+                for( int i = 0; i < 5; ++i )
+                    nBorder |= int(_SetWW8_BRC( 9 , brc[ i ], pSty->HasParaSprm( aVer9Ids[ i ] )))<<i;
+            }
         }
         else {
             OSL_ENSURE( pSty || pPap, "WW8PLCFx_Cp_FKP and WW8RStyle "
@@ -1256,9 +1286,17 @@ static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRC* brc, WW8PLCFx_Cp_FKP* pPa
     return nBorder;
 }
 
-void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace, sal_uInt8 nCol, short nIdx,
-    sal_uInt16 nOOIndex, sal_uInt16 nWWIndex, short *pSize=0)
+void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace,
+    sal_uInt32 cv, short nIdx, sal_uInt16 nOOIndex, sal_uInt16 nWWIndex,
+    short *pSize=0)
 {
+    // LO cannot handle outset/inset (new in WW9 BRC) so fall back same as WW8
+    if ( nIdx == 0x1A || nIdx == 0x1B )
+    {
+        nIdx = (nIdx == 0x1A) ? 0x12 : 0x11;
+        cv = 0xc0c0c0;
+    }
+
     ::editeng::SvxBorderStyle const eStyle(
             ::editeng::ConvertBorderStyleFromWord(nIdx));
 
@@ -1269,10 +1307,9 @@ void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace, sal_uInt
     aLine.SetWidth(fConverted);
 
     //No AUTO for borders as yet, so if AUTO, use BLACK
-    if (nCol == 0)
-        nCol = 1;
+    ColorData col = (cv==0xff000000) ? COL_BLACK : msfilter::util::BGRToRGB(cv);
 
-    aLine.SetColor(SwWW8ImplReader::GetCol(nCol));
+    aLine.SetColor(col);
 
     if (pSize)
         pSize[nWWIndex] = fConverted + nSpace;
@@ -1282,64 +1319,32 @@ void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace, sal_uInt
 
 }
 
-void Set1Border(bool bVer67, SvxBoxItem &rBox, const WW8_BRC& rBor,
-    sal_uInt16 nOOIndex, sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
-{
-    sal_uInt8 nCol;
-    short nSpace, nIdx;
-    short nLineThickness = rBor.DetermineBorderProperties(bVer67,&nSpace,&nCol,
-        &nIdx);
-
-    GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace, nCol, nIdx, nOOIndex, nWWIndex, pSize );
-
-}
-
-static bool lcl_IsBorder(bool bVer67, const WW8_BRC* pbrc, bool bChkBtwn = false)
+void Set1Border(SvxBoxItem &rBox, const WW8_BRCVer9& rBor, sal_uInt16 nOOIndex,
+    sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
 {
-    if( bVer67  )
-        return ( pbrc[WW8_TOP  ].aBits1[0] & 0x18 ) ||  // brcType  != 0
-               ( pbrc[WW8_LEFT ].aBits1[0] & 0x18 ) ||
-               ( pbrc[WW8_BOT  ].aBits1[0] & 0x18 ) ||
-               ( pbrc[WW8_RIGHT].aBits1[0] & 0x18 ) ||
-               ( bChkBtwn && ( pbrc[WW8_BETW ].aBits1[0] )) ||
-               //can have dotted and dashed with a brcType of 0
-               ( (pbrc[WW8_TOP  ].aBits1[0] & 0x07)+1 > 6) ||
-               ( (pbrc[WW8_LEFT ].aBits1[0] & 0x07)+1 > 6) ||
-               ( (pbrc[WW8_BOT  ].aBits1[0] & 0x07)+1 > 6) ||
-               ( (pbrc[WW8_RIGHT].aBits1[0] & 0x07)+1 > 6) ||
-               ( bChkBtwn && ( (pbrc[WW8_BETW ].aBits1[0] & 0x07)+1 > 6))
-               ;
-                // Abfrage auf 0x1f statt 0x18 ist noetig, da zumindest einige
-                // WW-Versionen ( 6.0 US ) bei dotted brcType auf 0 setzen
-    else
-        return pbrc[WW8_TOP  ].aBits1[1] ||         // brcType  != 0
-               pbrc[WW8_LEFT ].aBits1[1] ||
-               pbrc[WW8_BOT  ].aBits1[1] ||
-               pbrc[WW8_RIGHT].aBits1[1] ||
-               (bChkBtwn && pbrc[WW8_BETW ].aBits1[1]);
-}
+    short nSpace;
+    short nLineThickness = rBor.DetermineBorderProperties(&nSpace);
 
-bool SwWW8ImplReader::IsBorder(const WW8_BRC* pbrc, bool bChkBtwn) const
-{
-    return lcl_IsBorder(bVer67, pbrc, bChkBtwn);
-}
+    GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace,
+        rBor.cv(), rBor.brcType(), nOOIndex, nWWIndex, pSize );
 
-bool WW8_BRC::IsEmpty(bool bVer67) const
-{
-    return (IsBlank() || IsZeroed(bVer67));
 }
 
-bool WW8_BRC::IsBlank() const
+static bool lcl_IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false)
 {
-    return (aBits1[0] == 0xff && aBits1[1] == 0xff);
+    return pbrc[WW8_TOP  ].brcType() ||         // brcType  != 0
+           pbrc[WW8_LEFT ].brcType() ||
+           pbrc[WW8_BOT  ].brcType() ||
+           pbrc[WW8_RIGHT].brcType() ||
+           (bChkBtwn && pbrc[WW8_BETW ].brcType());
 }
 
-bool WW8_BRC::IsZeroed(bool bVer67) const
+bool SwWW8ImplReader::IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn) const
 {
-    return (!(bVer67 ? (aBits1[0] & 0x001f) : aBits1[1]));
+    return lcl_IsBorder(pbrc, bChkBtwn);
 }
 
-bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRC* pbrc,
+bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRCVer9* pbrc,
     short *pSizeArray, sal_uInt8 nSetBorders) const
 {
     bool bChange = false;
@@ -1355,10 +1360,10 @@ bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRC* pbrc,
     for( int i = 0, nEnd = 8; i < nEnd; i += 2 )
     {
         // ungueltige Borders ausfiltern
-        const WW8_BRC& rB = pbrc[ aIdArr[ i ] ];
-        if( !rB.IsEmpty(bVer67))
+        const WW8_BRCVer9& rB = pbrc[ aIdArr[ i ] ];
+        if( !rB.isNil() && rB.brcType() )
         {
-            Set1Border(bVer67, rBox, rB, aIdArr[i+1], aIdArr[i], pSizeArray, false);
+            Set1Border(rBox, rB, aIdArr[i+1], aIdArr[i], pSizeArray, false);
             bChange = true;
         }
         else if ( nSetBorders & (1 << aIdArr[i]) )
@@ -1381,18 +1386,14 @@ bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRC* pbrc,
 }
 
 bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
-    const WW8_BRC& aRightBrc) const
+    const WW8_BRCVer9& aRightBrc) const
 {
-    bool bRet = (
-                ( bVer67 ? (aRightBrc.aBits1[ 0 ] & 0x20 )
-                         : (aRightBrc.aBits2[ 1 ] & 0x20 ) )
-                && (pSizeArray && pSizeArray[WW8_RIGHT])
-                );
+    bool bRet = aRightBrc.fShadow() && pSizeArray && pSizeArray[WW8_RIGHT];
     if (bRet)
     {
         rShadow.SetColor(Color(COL_BLACK));
     //i120718
-        short nVal = aRightBrc.DetermineBorderProperties(bVer67);
+        short nVal = aRightBrc.DetermineBorderProperties();
     //End
         if (nVal < 0x10)
             nVal = 0x10;
@@ -1403,28 +1404,17 @@ bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
     return bRet;
 }
 
-void SwWW8ImplReader::GetBorderDistance(const WW8_BRC* pbrc,
+void SwWW8ImplReader::GetBorderDistance(const WW8_BRCVer9* pbrc,
     Rectangle& rInnerDist) const
 {
-    // 'dptSpace' is stored in 3 bits of 'Border Code (BRC)'
-    if (bVer67)
-    {
-        rInnerDist = Rectangle(((pbrc[ 1 ].aBits1[1] >> 3) & 0x1f) * 20,
-                               ((pbrc[ 0 ].aBits1[1] >> 3) & 0x1f) * 20,
-                               ((pbrc[ 3 ].aBits1[1] >> 3) & 0x1f) * 20,
-                               ((pbrc[ 2 ].aBits1[1] >> 3) & 0x1f) * 20 );
-    }
-    else
-    {
-        rInnerDist = Rectangle( (pbrc[ 1 ].aBits2[1]       & 0x1f) * 20,
-                                (pbrc[ 0 ].aBits2[1]       & 0x1f) * 20,
-                                (pbrc[ 3 ].aBits2[1]       & 0x1f) * 20,
-                                (pbrc[ 2 ].aBits2[1]       & 0x1f) * 20 );
-    }
+    rInnerDist = Rectangle( pbrc[ 1 ].dptSpace() * 20,
+                            pbrc[ 0 ].dptSpace() * 20,
+                            pbrc[ 3 ].dptSpace() * 20,
+                            pbrc[ 2 ].dptSpace() * 20 );
 }
 
 bool SwWW8ImplReader::SetFlyBordersShadow(SfxItemSet& rFlySet,
-    const WW8_BRC *pbrc, short *pSizeArray) const
+    const WW8_BRCVer9 *pbrc, short *pSizeArray) const
 {
     bool bShadowed = false;
     if (IsBorder(pbrc))
@@ -1567,7 +1557,7 @@ void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8PLCFx_Cp_FKP* pPap)
     }
 
     if( ::lcl_ReadBorders( bVer67, brc, pPap ))     // Umrandung
-        bBorderLines = ::lcl_IsBorder( bVer67, brc );
+        bBorderLines = ::lcl_IsBorder( brc );
 
     /*
      #i8798#
@@ -1685,7 +1675,7 @@ void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle* pStyle)
     }
 
     if (::lcl_ReadBorders(bVer67, brc, 0, pStyle))      // Umrandung
-        bBorderLines = ::lcl_IsBorder(bVer67, brc);
+        bBorderLines = ::lcl_IsBorder(brc);
 
     /*
      #i8798#
@@ -1882,16 +1872,16 @@ WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
     sal_Int16 nLeBorderMgn( 0L );
     if ( !bAutoWidth )
     {
-        sal_Int16 nTemp = rWW.brc[WW8_LEFT].DetermineBorderProperties(rWW.bVer67,
-            &nLeBorderMgn);
+        WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
+        sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
         nLeBorderMgn = nLeBorderMgn + nTemp;
     }
     // determine right border distance
     sal_Int16 nRiBorderMgn( 0L );
     if ( !bAutoWidth )
     {
-        sal_Int16 nTemp = rWW.brc[WW8_RIGHT].DetermineBorderProperties(rWW.bVer67,
-            &nRiBorderMgn);
+        WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
+        sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
         nRiBorderMgn = nRiBorderMgn + nTemp;
     }
     if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
@@ -1943,9 +1933,9 @@ WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
         Word has a curious bug where the offset stored do not take into
         account the internal distance from the corner both
         */
+        WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
         sal_Int16 nLeLMgn = 0;
-        sal_Int16 nTemp = rWW.brc[WW8_LEFT].DetermineBorderProperties(rWW.bVer67,
-            &nLeLMgn);
+        sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
         nLeLMgn = nLeLMgn + nTemp;
 
         if (nLeLMgn)
@@ -2014,7 +2004,7 @@ WW8FlySet::WW8FlySet(SwWW8ImplReader& rReader, const WW8FlyPara* pFW,
     Put( aSurround );
 
     short aSizeArray[5]={0};
-    rReader.SetFlyBordersShadow(*this,(const WW8_BRC*)pFW->brc,&aSizeArray[0]);
+    rReader.SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
 
     // der 5. Parameter ist immer 0, daher geht beim Cast nix verloren
 
@@ -2058,7 +2048,10 @@ WW8FlySet::WW8FlySet( SwWW8ImplReader& rReader, const SwPaM* pPaM,
     region is translated spacing around the graphic to those sides, and the
     bottom and right shadow size is added to the graphic size.
     */
-    if (rReader.SetFlyBordersShadow( *this, rPic.rgbrc, &aSizeArray[0]))
+    WW8_BRCVer9 brcVer9[4];
+    for (int i = 0; i < 4; i++)
+        brcVer9[i] = rPic.rgbrc[i];
+    if (rReader.SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
     {
         Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
         Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
@@ -4672,7 +4665,7 @@ void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
         // CtrlStack und wieder runter
         bHasBorder = true;
 
-        WW8_BRC5 aBrcs;   // Top, Left, Bottom, Right, Between
+        WW8_BRCVer9_5 aBrcs;   // Top, Left, Bottom, Right, Between
         sal_uInt8 nBorder;
 
         if( pAktColl )
@@ -4728,11 +4721,11 @@ void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
     }
 }
 
-void SwWW8ImplReader::Read_CharBorder(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen )
+void SwWW8ImplReader::Read_CharBorder(sal_uInt16 nId, const sal_uInt8* pData, short nLen )
 {
     //Ignore this old border type
-    if (!bVer67 && pPlcxMan && pPlcxMan->GetChpPLCF()->HasSprm(0xCA72))
-        return;
+    //if (!bVer67 && pPlcxMan && pPlcxMan->GetChpPLCF()->HasSprm(0xCA72))
+    //    return;
 
     if( nLen < 0 )
     {
@@ -4747,13 +4740,15 @@ void SwWW8ImplReader::Read_CharBorder(sal_uInt16 /*nId*/, const sal_uInt8* pData
         {
             SvxBoxItem aBoxItem(RES_CHRATR_BOX);
             aBoxItem = *pBox;
-            WW8_BRC aBrc;
-            _SetWW8_BRC(bVer67, aBrc, pData);
+            WW8_BRCVer9 aBrc;
+            int nBrcVer = (nId == NS_sprm::LN_CBorder) ? 9 : (bVer67 ? 6 : 8);
+
+            _SetWW8_BRC(nBrcVer, aBrc, pData);
 
-            Set1Border(bVer67, aBoxItem, aBrc, BOX_LINE_TOP, 0, 0, true);
-            Set1Border(bVer67, aBoxItem, aBrc, BOX_LINE_BOTTOM, 0, 0, true);
-            Set1Border(bVer67, aBoxItem, aBrc, BOX_LINE_LEFT, 0, 0, true);
-            Set1Border(bVer67, aBoxItem, aBrc, BOX_LINE_RIGHT, 0, 0, true);
+            Set1Border(aBoxItem, aBrc, BOX_LINE_TOP, 0, 0, true);
+            Set1Border(aBoxItem, aBrc, BOX_LINE_BOTTOM, 0, 0, true);
+            Set1Border(aBoxItem, aBrc, BOX_LINE_LEFT, 0, 0, true);
+            Set1Border(aBoxItem, aBrc, BOX_LINE_RIGHT, 0, 0, true);
             NewAttr( aBoxItem );
 
             short aSizeArray[WW8_RIGHT+1]={0}; aSizeArray[WW8_RIGHT] = 1;
@@ -5845,6 +5840,7 @@ const wwSprmDispatcher *GetWW8SprmDispatcher()
         {NS_sprm::LN_CDttmRMarkDel, 0},
                                                      //chp.dttmRMarkDel;DTTM;long;
         {0x6865, &SwWW8ImplReader::Read_CharBorder}, //"sprmCBrc" chp.brc;BRC;long;
+        {0xca72, &SwWW8ImplReader::Read_CharBorder}, //"sprmCBorder" chp.brc;BRC;long;
         {0x4866, &SwWW8ImplReader::Read_CharShadow}, //"sprmCShd" chp.shd;SHD;short;
         {0x4867, 0},                                 //"sprmCIdslRMarkDel"
                                                      //chp.idslRMReasonDel;an index
@@ -6067,10 +6063,11 @@ const wwSprmDispatcher *GetWW8SprmDispatcher()
         {0xD634, 0},                                 //undocumented
         {0xD632, 0},                                 //undocumented
         {0xD238, 0},                                 //undocumented sep
-        {0xC64E, 0},                                 //undocumented
-        {0xC64F, 0},                                 //undocumented
-        {0xC650, 0},                                 //undocumented
-        {0xC651, 0},                                 //undocumented
+        {0xC64E, &SwWW8ImplReader::Read_Border},     //"sprmPBorderTop"
+        {0xC64F, &SwWW8ImplReader::Read_Border},     //"sprmPBorderLeft"
+        {0xC650, &SwWW8ImplReader::Read_Border},     //"sprmPBorderBottom"
+        {0xC651, &SwWW8ImplReader::Read_Border},     //"sprmPBorderRight"
+        {0xC652, &SwWW8ImplReader::Read_Border},     //"sprmPBorderBetween"
         {0xF661, 0},                                 //undocumented
         {0x4873, &SwWW8ImplReader::Read_Language},   //"sprmCRgLid0" chp.rglid[0];
                                                      //LID: for non-Far East text;
diff --git a/sw/source/filter/ww8/ww8scan.cxx b/sw/source/filter/ww8/ww8scan.cxx
index 646c4eb..7354ab0 100644
--- a/sw/source/filter/ww8/ww8scan.cxx
+++ b/sw/source/filter/ww8/ww8scan.cxx
@@ -18,6 +18,7 @@
  */
 
 #include "ww8scan.hxx"
+#include "ww8par.hxx"
 
 #include <functional>
 #include <algorithm>
@@ -739,10 +740,11 @@ const wwSprmSearcher *wwSprmParser::GetWW8SprmSearcher()
         {0xD632, 0, L_VAR}, // undocumented
         {0xD634, 0, L_VAR}, // undocumented
         {0xD238, 0, L_VAR}, // undocumented sep
-        {0xC64E, 0, L_VAR}, // undocumented
-        {0xC64F, 0, L_VAR}, // undocumented
-        {0xC650, 0, L_VAR}, // undocumented
-        {0xC651, 0, L_VAR}, // undocumented
+        {0xC64E, 0, L_VAR}, // "sprmPBorderTop"
+        {0xC64F, 0, L_VAR}, // "sprmPBorderLeft"
+        {0xC650, 0, L_VAR}, // "sprmPBorderBottom"
+        {0xC651, 0, L_VAR}, // "sprmPBorderRight"
+        {0xC652, 0, L_VAR}, // "sprmPBorderBetween"
         {0xF661, 3, L_FIX}, // undocumented
         {0x4873, 2, L_FIX}, // "sprmCRgLid0" chp.rglid[0];LID: for non-FE text
         {0x4874, 2, L_FIX}, // "sprmCRgLid1" chp.rglid[1];LID: for Far East text
@@ -1256,8 +1258,64 @@ WW8_CP WW8PLCFx_PCD::AktPieceStartFc2Cp( WW8_FC nStartPos )
 
 //      Helper routines for all
 
-short WW8_BRC::DetermineBorderProperties(bool bVer67, short *pSpace,
-    sal_uInt8 *pCol, short *pIdx) const
+// Convert BRC from WW6 to WW8 format
+WW8_BRC::WW8_BRC(const WW8_BRCVer6& brcVer6)
+{
+    sal_uInt8 _dptLineWidth = brcVer6.dxpLineWidth(),
+              _brcType = brcVer6.brcType();
+
+    if (_dptLineWidth > 5) // this signifies dashed(6) or dotted(7) line
+    {
+        _brcType = _dptLineWidth;
+        _dptLineWidth = 1;
+    }
+    _dptLineWidth *= 6; // convert units from 0.75pt to 1/8pt
+
+    *this = WW8_BRC(_dptLineWidth, _brcType, brcVer6.ico(), brcVer6.dxpSpace(),
+        brcVer6.fShadow(), false);
+}
+
+// Convert BRC from WW8 to WW6 format
+WW8_BRCVer6::WW8_BRCVer6(const WW8_BRC& brcVer8)
+{
+    sal_uInt8 _brcType = brcVer8.brcType();
+    sal_uInt8 _dxpLineWidth = std::max(brcVer8.dptLineWidth() / 6, 7);
+    if (_brcType == 5 || _brcType == 6 )
+    {
+        _dxpLineWidth = _brcType;
+        _brcType = 1;
+    }
+    else if (_brcType > 3)
+    {
+        _brcType = 1;
+    }
+    *this = WW8_BRCVer6(_dxpLineWidth, _brcType, brcVer8.ico(),
+        brcVer8.dptSpace(), brcVer8.fShadow());
+}
+
+// Convert BRC from WW8 to WW9 format
+WW8_BRCVer9::WW8_BRCVer9(const WW8_BRC& brcVer8)
+{
+    if (brcVer8.isNil()) {
+        UInt32ToSVBT32(0, aBits1);
+        UInt32ToSVBT32(0xffffffff, aBits2);
+    }
+    else
+    {
+        sal_uInt32 _cv = brcVer8.ico() == 0 ? 0xff000000 // "auto" colour
+            : wwUtility::RGBToBGR(SwWW8ImplReader::GetCol(brcVer8.ico()));
+        *this = WW8_BRCVer9(_cv, brcVer8.dptLineWidth(), brcVer8.brcType(),
+            brcVer8.dptSpace(), brcVer8.fShadow(), brcVer8.fFrame());
+    }
+}
+
+short WW8_BRC::DetermineBorderProperties(short *pSpace) const
+{
+    WW8_BRCVer9 brcVer9(*this);
+    return brcVer9.DetermineBorderProperties(pSpace);
+}
+
+short WW8_BRCVer9::DetermineBorderProperties(short *pSpace) const
 {
     /*
         Word does not factor the width of the border into the width/height
@@ -1266,89 +1324,61 @@ short WW8_BRC::DetermineBorderProperties(bool bVer67, short *pSpace,
         our calculations
     */
     short nMSTotalWidth;
-    sal_uInt8 nCol;
-    short nIdx,nSpace;
-    if( bVer67 )
-    {
-        sal_uInt16 aBrc1 = SVBT16ToShort(aBits1);
-        nCol = static_cast< sal_uInt8 >((aBrc1 >> 6) & 0x1f);   // aBor.ico
-        nSpace = (aBrc1 & 0xF800) >> 11;
-
-        nMSTotalWidth = aBrc1 & 0x07;
-        nIdx = (aBrc1 & 0x18) >> 3;
-        //Dashed/Dotted unsets double/thick
-        if (nMSTotalWidth > 5)
-        {
-            nIdx = nMSTotalWidth;
-            nMSTotalWidth=1;
-        }
-        nMSTotalWidth = nMSTotalWidth * nIdx * 15;
-    }
-    else
-    {
-        nIdx = aBits1[1];
-        nCol = aBits2[0];   // aBor.ico
-        nSpace = aBits2[1] & 0x1F; //space between line and object
 
-        //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
-        nMSTotalWidth  = aBits1[ 0 ] * 20 / 8;
+    //Specification in 8ths of a point, 1 Point = 20 Twips, so by 2.5
+    nMSTotalWidth  = (short)dptLineWidth() * 20 / 8;
 
-        //Figure out the real size of the border according to word
-        switch (nIdx)
-        {
-            //Note that codes over 25 are undocumented, and I can't create
-            //these 4 here in the wild.
-            case 2:
-            case 4:
-            case 5:
-            case 22:
-                OSL_FAIL("Can't create these from the menus, please report");
-            default:
-            case 23:    //Only 3pt in the menus, but honours the size setting.
-                break;
-            case 10:
-                /*
-                triple line is five times the width of an ordinary line,
-                except that the smallest 1/4 point size appears to have
-                exactly the same total border width as a 3/4 point size
-                ordinary line, i.e. three times the nominal line width.  The
-                second smallest 1/2 point size appears to have exactly the
-                total border width as a 2 1/4 border, i.e 4.5 times the size.
-                */
-                if (nMSTotalWidth == 5)
-                    nMSTotalWidth*=3;
-                else if (nMSTotalWidth == 10)
-                    nMSTotalWidth = nMSTotalWidth*9/2;
-                else
-                    nMSTotalWidth*=5;
-                break;
-            case 20:
-                /*
-                wave, the dimensions appear to be created by the drawing of
-                the wave, so we have only two possibilites in the menus, 3/4
-                point is equal to solid 3 point. This calculation seems to
-                match well to results.
-                */
-                nMSTotalWidth +=45;
-                break;
-            case 21:
-                /*
-                double wave, the dimensions appear to be created by the
-                drawing of the wave, so we have only one possibilites in the
-                menus, that of 3/4 point is equal to solid 3 point. This
-                calculation seems to match well to results.
-                */
-                nMSTotalWidth += 45*2;
-                break;
-        }
+    //Figure out the real size of the border according to word
+    switch (brcType())
+    {
+        //Note that codes over 25 are undocumented, and I can't create
+        //these 4 here in the wild.
+        case 2:
+        case 4:
+        case 5:
+        case 22:
+            OSL_FAIL("Can't create these from the menus, please report");
+        default:
+        case 23:    //Only 3pt in the menus, but honours the size setting.
+            break;
+        case 10:
+            /*
+            triple line is five times the width of an ordinary line,
+            except that the smallest 1/4 point size appears to have
+            exactly the same total border width as a 3/4 point size
+            ordinary line, i.e. three times the nominal line width.  The
+            second smallest 1/2 point size appears to have exactly the
+            total border width as a 2 1/4 border, i.e 4.5 times the size.
+            */
+            if (nMSTotalWidth == 5)
+                nMSTotalWidth*=3;
+            else if (nMSTotalWidth == 10)
+                nMSTotalWidth = nMSTotalWidth*9/2;
+            else
+                nMSTotalWidth*=5;
+            break;
+        case 20:
+            /*
+            wave, the dimensions appear to be created by the drawing of
+            the wave, so we have only two possibilites in the menus, 3/4
+            point is equal to solid 3 point. This calculation seems to
+            match well to results.
+            */
+            nMSTotalWidth +=45;
+            break;
+        case 21:
+            /*
+            double wave, the dimensions appear to be created by the
+            drawing of the wave, so we have only one possibilites in the
+            menus, that of 3/4 point is equal to solid 3 point. This
+            calculation seems to match well to results.
+            */
+            nMSTotalWidth += 45*2;
+            break;
     }
 
-    if (pIdx)
-        *pIdx = nIdx;
     if (pSpace)
-        *pSpace = nSpace*20;
-    if (pCol)
-        *pCol = nCol;
+        *pSpace = (short)dptSpace() * 20; // convert from points to twips
     return nMSTotalWidth;
 }
 
diff --git a/sw/source/filter/ww8/ww8struc.hxx b/sw/source/filter/ww8/ww8struc.hxx
index 52d68fc..2fe7c57 100644
--- a/sw/source/filter/ww8/ww8struc.hxx
+++ b/sw/source/filter/ww8/ww8struc.hxx
@@ -226,7 +226,7 @@ struct WW8_FFN : public WW8_FFN_BASE
                                         // font does not exist on this system.
 };
 
-struct WW8_BRCVer6  // alter Border Code
+struct WW8_BRCVer6  // BoRder Code (WW6 version)
 {
     SVBT16 aBits1;
 //  sal_uInt16 dxpLineWidth : 3;// 0007 When dxpLineWidth is 0, 1, 2, 3, 4, or 5, this field is the width of
@@ -238,36 +238,135 @@ struct WW8_BRCVer6  // alter Border Code
 //  sal_uInt16 ico : 5;         // 07C0 color code (see chp.ico)
 //  sal_uInt16 dxpSpace : 5;    // F800 width of space to maintain between border and text within border.
                             //      Must be 0 when BRC is a substructure of the TC.  Stored in points for Windows.
+    sal_uInt8 dxpLineWidth() const
+        { return aBits1[0] & 0x07; }
+    sal_uInt8 brcType() const
+        { return (aBits1[0] & 0x18) >> 3; }
+    bool fShadow() const
+        { return !!(aBits1[0] & 0x20); }
+    sal_uInt8 ico() const
+        { return ((aBits1[0] & 0xc0) >> 6) | ((aBits1[1] & 0x07) << 2); }
+    sal_uInt8 dxpSpace() const
+        { return aBits1[1] >> 3; }
+
+    WW8_BRCVer6(sal_uInt8 _dxpLineWidth, sal_uInt8 _brcType, sal_uInt8 _ico,
+        sal_uInt8 _dxpSpace, bool _fShadow)
+    {
+        assert(_dxpSpace < 0x20);
+        assert(_brcType <= 3);
+        assert(_ico < 32);
+        aBits1[0] = _dxpLineWidth | (_brcType << 3) | ((sal_uInt8)_fShadow << 5)
+            | ((_ico << 6) & 0xc0);
+        aBits1[1] = (_ico >> 2) | (_dxpSpace << 3);
+    }
+    // Convert BRC from WW8 to WW6 format
+    WW8_BRCVer6(const class WW8_BRC& brcVer8);
 };
 
-class WW8_BRC      // Border Code
+struct WW8_BRC  // BoRder Code (WW8 version)
+// Documented at http://msdn.microsoft.com/en-us/library/dd952599.aspx
 {
-public:
     SVBT16 aBits1;
     SVBT16 aBits2;
-//  sal_uInt16 dxpLineWidth : 3;// 0007 When dxpLineWidth is 0, 1, 2, 3, 4, or 5, this field is the width of
-                            //      a single line of border in units of 0.75 points
-                            //      Must be nonzero when brcType is nonzero.
-                            //      6 == dotted, 7 == dashed.
-//  sal_uInt16 brcType : 2;     // 0018 border type code: 0 == none, 1 == single, 2 == thick, 3 == double
-//  sal_uInt16 fShadow : 1;     // 0020 when 1, border is drawn with shadow. Must be 0 when BRC is a substructure of the TC
-//  sal_uInt16 ico : 5;         // 07C0 color code (see chp.ico)
-//  sal_uInt16 dxpSpace : 5;    // F800 width of space to maintain between border and text within border.
-                            //      Must be 0 when BRC is a substructure of the TC.  Stored in points for Windows.
+//  sal_uInt8 dptLineWidth;
+//  sal_uInt8 brcType;
+//  sal_uInt8 ico;
+//  sal_uInt8 dptSpace : 5
+//  bool fShadow : 1;
+//  bool fFrame : 1;
+//  bool fReserved : 1;
     WW8_BRC()
     {
         memset(aBits1, 0, sizeof(aBits1));
         memset(aBits2, 0, sizeof(aBits2));
     }
-    short DetermineBorderProperties (bool bVer67, short *pSpace=0,
-        sal_uInt8 *pCol=0, short *pIdx=0) const;
-    bool IsEmpty(bool bVer67) const;
-    bool IsZeroed(bool bVer67) const;
-    bool IsBlank() const;
+
+    sal_uInt8 dptLineWidth() const // border line width (1/8pt)
+        { return aBits1[0]; }
+    sal_uInt8 brcType() const      // border type (eg single, double, dotted)
+        { return aBits1[1]; }
+    sal_uInt8 ico() const          // colour index, 1-17 or 0=auto
+        { return aBits2[0]; }
+    sal_uInt8 dptSpace() const     // space between text & border (pt)
+        { return aBits2[1] & 0x1f; }
+    bool fShadow() const           // shadow effect
+        { return !!(aBits2[1] & 0x20); }
+    bool fFrame() const            // 3D frame effect
+        { return !!(aBits2[1] & 0x40); }
+    bool isNil() const             // nil = no border
+        { return aBits1[0] == 0xff && aBits1[1] == 0xff; }
+
+    WW8_BRC(sal_uInt8 _dptLineWidth, sal_uInt8 _brcType, sal_uInt8 _ico,
+        sal_uInt8 _dptSpace, bool _fShadow, bool _fFrame)
+    {
+        assert(_dptSpace < 0x20);
+        aBits1[0] = _dptLineWidth;
+        aBits1[1] = _brcType;
+        aBits2[0] = _ico;
+        aBits2[1] = _dptSpace | ((sal_uInt8)_fShadow << 5)
+            | ((sal_uInt8)_fFrame << 6);
+    }
+    // Convert BRC from WW6 to WW8 format
+    WW8_BRC(const WW8_BRCVer6& brcVer6);
+
+    // Returns LO border width in twips=1/20pt, taking into account brcType
+    short DetermineBorderProperties(short *pSpace=0) const;
 };
 
 typedef WW8_BRC WW8_BRC5[5];        // 5 * Border Code
 
+struct WW8_BRCVer9  // BoRder Code (WW9 version)
+// Documented at http://msdn.microsoft.com/en-us/library/dd907496.aspx
+{
+    SVBT32 aBits1; // border colour (RGB)
+    SVBT32 aBits2;
+//  sal_uInt8 dptLineWidth;   // border line width (1/8pt)
+//  sal_uInt8 brcType;        // border type (eg single, double, dotted)
+//  sal_uInt8 dptSpace : 5;   // space between text & border (pt)
+//  bool fShadow : 1;         // border has shadow effect
+//  bool fFrame : 1;          // border has 3D effect
+//  sal_uInt16 fReserved : 9; // unused
+    WW8_BRCVer9()
+    {
+        memset(aBits1, 0, sizeof(aBits1));
+        memset(aBits2, 0, sizeof(aBits2));
+    }
+
+    sal_uInt32 cv() const          // colour value (BGR)
+        { return SVBT32ToUInt32(aBits1); }
+    sal_uInt8 dptLineWidth() const // border line width (1/8pt)
+        { return aBits2[0]; }
+    sal_uInt8 brcType() const      // border type (eg single, double, dotted)
+        { return aBits2[1]; }
+    sal_uInt8 dptSpace() const     // space between text & border (pt)
+        { return aBits2[2] & 0x1f; }
+    bool fShadow() const           // shadow effect
+        { return !!(aBits2[2] & 0x20); }
+    bool fFrame() const            // 3D frame effect
+        { return !!(aBits2[2] & 0x40); }
+    bool isNil() const             // nil = no border
+        { return SVBT32ToUInt32(aBits2) == 0xffffffff; }
+
+    WW8_BRCVer9(sal_uInt32 _cv, sal_uInt8 _dptLineWidth, sal_uInt8 _brcType,
+        sal_uInt8 _dptSpace, bool _fShadow, bool _fFrame)
+    {
+        assert(_dptSpace < 0x20);
+        UInt32ToSVBT32(_cv, aBits1);
+        aBits2[0] = _dptLineWidth;
+        aBits2[1] = _brcType;
+        aBits2[2] = _dptSpace | ((sal_uInt8)_fShadow << 5)
+            | ((sal_uInt8)_fFrame << 6);
+        aBits2[3] = 0;
+    }
+    // Convert BRC from WW8 to WW9 format
+    WW8_BRCVer9(const WW8_BRC& brcVer8);
+
+    // Returns LO border width in twips=1/20pt, taking into account brcType
+    short DetermineBorderProperties(short *pSpace=0) const;
+};
+
+typedef WW8_BRCVer9 WW8_BRCVer9_5[5];        // 5 * Border Code
+
 enum BRC_Sides
 {
     WW8_TOP = 0, WW8_LEFT = 1, WW8_BOT = 2, WW8_RIGHT = 3, WW8_BETW = 4
@@ -444,7 +543,7 @@ struct WW8_TCell    // hiermit wird weitergearbeitet (entspricht weitestgehend d
                                                     //          2 bottom
     sal_uInt16 fUnused      : 7;// reserved - nicht loeschen: macht das sal_uInt16 voll !!
 
-    WW8_BRC rgbrc[4];               // border codes
+    WW8_BRCVer9 rgbrc[4];   // border codes
 //notational convenience for referring to brcTop, brcLeft, etc fields.
 //  BRC brcTop;             // specification of the top border of a table cell
 //  BRC brcLeft;            // specification of left border of table row


More information about the Libreoffice-commits mailing list