Char highlight: convert LO character background to MSO highlighting
DOC export has a good approximating algorithm for that
so use it everywhere.
In RTF case use the default color table which is added
also by MSO Word. With that highlight colors are also added to
the table.
Change-Id: Ie4827a933c316d4dc0c0c7a32d8cf319477d1bf9
diff --git a/filter/source/msfilter/util.cxx b/filter/source/msfilter/util.cxx
index 958f0b8..9031a77 100644
--- a/filter/source/msfilter/util.cxx
+++ b/filter/source/msfilter/util.cxx
@@ -12,6 +12,7 @@
#include <unotools/fontcvt.hxx>
#include <unotools/fontdefs.hxx>
#include <vcl/svapp.hxx>
#include <vcl/salbtype.hxx>
#include <filter/msfilter/util.hxx>
#include <boost/scoped_ptr.hpp>
#include <unordered_map>
@@ -1350,6 +1351,47 @@ bool HasTextBoxContent(sal_uInt32 nShapeType)
return true;
}
}
sal_uInt8 TransColToIco( const Color& rCol )
{
sal_uInt8 nCol = 0; // ->Auto
switch( rCol.GetColor() )
{
case COL_BLACK: nCol = 1; break;
case COL_BLUE: nCol = 9; break;
case COL_GREEN: nCol = 11; break;
case COL_CYAN: nCol = 10; break;
case COL_RED: nCol = 13; break;
case COL_MAGENTA: nCol = 12; break;
case COL_BROWN: nCol = 14; break;
case COL_GRAY: nCol = 15; break;
case COL_LIGHTGRAY: nCol = 16; break;
case COL_LIGHTBLUE: nCol = 2; break;
case COL_LIGHTGREEN: nCol = 4; break;
case COL_LIGHTCYAN: nCol = 3; break;
case COL_LIGHTRED: nCol = 6; break;
case COL_LIGHTMAGENTA: nCol = 5; break;
case COL_YELLOW: nCol = 7; break;
case COL_WHITE: nCol = 8; break;
case COL_AUTO: nCol = 0; break;
default:
static const ColorData aColArr[ 16 ] = {
COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
COL_LIGHTMAGENTA,COL_LIGHTRED, COL_YELLOW, COL_WHITE,
COL_BLUE, COL_CYAN, COL_GREEN, COL_MAGENTA,
COL_RED, COL_BROWN, COL_GRAY, COL_LIGHTGRAY
};
BitmapPalette aBmpPal(16);
for( sal_uInt16 i = 0; i < 16; ++i )
aBmpPal[i] = Color( aColArr[ i ] );
nCol = static_cast< sal_uInt8 >(aBmpPal.GetBestIndex( rCol ) + 1);
break;
}
return nCol;
}
}
}
diff --git a/include/filter/msfilter/util.hxx b/include/filter/msfilter/util.hxx
index c1bb36d..1164889 100644
--- a/include/filter/msfilter/util.hxx
+++ b/include/filter/msfilter/util.hxx
@@ -146,6 +146,15 @@ MSFILTER_DLLPUBLIC MSO_SPT GETVMLShapeType(const OString& aType);
*/
MSFILTER_DLLPUBLIC bool HasTextBoxContent(sal_uInt32 nShapeType);
/**
* Convert the input color value to an ico value (0..16)
*
* @param[in] rCol input color for conversion
*
* @return ico value [0..16]
**/
MSFILTER_DLLPUBLIC sal_uInt8 TransColToIco( const Color& rCol );
}
}
diff --git a/sw/qa/extras/globalfilter/data/char_background.odt b/sw/qa/extras/globalfilter/data/char_background.odt
new file mode 100644
index 0000000..d2dcea0
--- /dev/null
+++ b/sw/qa/extras/globalfilter/data/char_background.odt
Binary files differ
diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx
index 888985b..9680a67 100644
--- a/sw/qa/extras/globalfilter/globalfilter.cxx
+++ b/sw/qa/extras/globalfilter/globalfilter.cxx
@@ -32,6 +32,7 @@ public:
void testCharHighlight();
void testCharHighlightBody();
void testMSCharBackgroundEditing();
void testCharBackgroundToHighlighting();
CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(testSwappedOutImageExport);
@@ -40,6 +41,7 @@ public:
CPPUNIT_TEST(testGraphicShape);
CPPUNIT_TEST(testCharHighlight);
CPPUNIT_TEST(testMSCharBackgroundEditing);
CPPUNIT_TEST(testCharBackgroundToHighlighting);
CPPUNIT_TEST_SUITE_END();
};
@@ -580,6 +582,77 @@ void Test::testMSCharBackgroundEditing()
}
}
void Test::testCharBackgroundToHighlighting()
{
// MSO highlighting has less kind of values so let's see how LO character background is converted
// to these values
const char* aFilterNames[] = {
"Rich Text Format",
"MS Word 97",
"Office Open XML Text",
};
for( size_t nFilter = 0; nFilter < SAL_N_ELEMENTS(aFilterNames); ++nFilter )
{
if (mxComponent.is())
mxComponent->dispose();
mxComponent = loadFromDesktop(getURLFromSrc("/sw/qa/extras/globalfilter/data/char_background.odt"),
"com.sun.star.text.TextDocument");
const OString sFailedMessage = OString("Failed on filter: ") + aFilterNames[nFilter];
SvtFilterOptions& rOpt = SvtFilterOptions::Get();
rOpt.SetCharBackground2Highlighting();
// Export the document and import again for a check
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
utl::MediaDescriptor aMediaDescriptor;
aMediaDescriptor["FilterName"] <<= OUString::createFromAscii(aFilterNames[nFilter]);
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
uno::Reference< lang::XComponent > xComponent(xStorable, uno::UNO_QUERY);
xComponent->dispose();
mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument");
// Check highlight color
const uno::Reference< text::XTextRange > xPara = getParagraph(1);
for( int nRun = 1; nRun <= 20; ++nRun )
{
const uno::Reference<beans::XPropertySet> xRun(getRun(xPara,nRun), uno::UNO_QUERY);
sal_Int32 nHighlightColor = 0;
switch( nRun )
{
case 1: nHighlightColor = 0x000000; break; //black
case 2: nHighlightColor = 0xffff00; break; //yellow
case 3: nHighlightColor = 0xff00ff; break; //magenta
case 4: nHighlightColor = 0x00ffff; break; //cyan
case 5: nHighlightColor = 0xffff00; break; //yellow
case 6: nHighlightColor = 0xff0000; break; //red
case 7: nHighlightColor = 0x0000ff; break; //blue
case 8: nHighlightColor = 0x00ff00; break; //green
case 9: nHighlightColor = 0x008000; break; //dark green
case 10: nHighlightColor = 0x800080; break; //dark magenta
case 11: nHighlightColor = 0x000080; break; //dark blue
case 12: nHighlightColor = 0x000000; break; //black
case 13: nHighlightColor = 0x808000; break; //dark yellow
case 14: nHighlightColor = 0x808080; break; //dark gray
case 15: nHighlightColor = 0x000000; break; //white
case 16: nHighlightColor = 0xff0000; break; //red
case 17: nHighlightColor = 0xC0C0C0; break; //light gray
case 18: nHighlightColor = 0x800000; break; //dark red
case 19: nHighlightColor = 0x008080; break; //dark cyan
case 20: nHighlightColor = 0xffffff; break; //white
}
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nHighlightColor, getProperty<sal_Int32>(xRun,"CharHighlight"));
}
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 2068e54b..b3cc593 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -5786,26 +5786,26 @@ void DocxAttributeOutput::EmbedFontStyle( const OUString& name, int tag, FontFam
FSEND );
}
OString DocxAttributeOutput::TransHighlightColor( const Color& rColor )
OString DocxAttributeOutput::TransHighlightColor( sal_uInt8 nIco )
{
switch (rColor.GetColor())
switch (nIco)
{
case 0x000000: return OString("black"); break;
case 0x0000ff: return OString("blue"); break;
case 0x00ffff: return OString("cyan"); break;
case 0x00ff00: return OString("green"); break;
case 0xff00ff: return OString("magenta"); break;
case 0xff0000: return OString("red"); break;
case 0xffff00: return OString("yellow"); break;
case 0xffffff: return OString("white"); break;
case 0x000080: return OString("darkBlue"); break;
case 0x008080: return OString("darkCyan"); break;
case 0x008000: return OString("darkGreen"); break;
case 0x800080: return OString("darkMagenta"); break;
case 0x800000: return OString("darkRed"); break;
case 0x808000: return OString("darkYellow"); break;
case 0x808080: return OString("darkGray"); break;
case 0xC0C0C0: return OString("lightGray"); break;
case 1: return OString("black"); break;
case 2: return OString("blue"); break;
case 3: return OString("cyan"); break;
case 4: return OString("green"); break;
case 5: return OString("magenta"); break;
case 6: return OString("red"); break;
case 7: return OString("yellow"); break;
case 8: return OString("white"); break;
case 9: return OString("darkBlue"); break;
case 10: return OString("darkCyan"); break;
case 11: return OString("darkGreen"); break;
case 12: return OString("darkMagenta"); break;
case 13: return OString("darkRed"); break;
case 14: return OString("darkYellow"); break;
case 15: return OString("darkGray"); break;
case 16: return OString("lightGray"); break;
default: return OString(); break;
}
}
@@ -6411,7 +6411,7 @@ void DocxAttributeOutput::CharBorder(
void DocxAttributeOutput::CharHighlight( const SvxBrushItem& rHighlight )
{
const OString sColor = TransHighlightColor( rHighlight.GetColor() );
const OString sColor = TransHighlightColor( msfilter::util::TransColToIco(rHighlight.GetColor()) );
if ( !sColor.isEmpty() )
{
m_pSerializer->singleElementNS( XML_w, XML_highlight,
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 58c89c8..bcbf38e 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -440,13 +440,13 @@ private:
FontPitch pitch, rtl_TextEncoding encoding );
/**
* Translate a color object to the corresponding HighlightColorValues enumaration item
* Translate an ico value to the corresponding HighlightColorValues enumaration item
*
* @param[in] rColor a color object to translate
* @param[in] nIco ico value [0..16]
* @return color name (e.g. "red"), if color is inside the enumeration's range
* empty string, otherwise
**/
OString TransHighlightColor( const Color& rColor );
static OString TransHighlightColor( sal_uInt8 nIco );
protected:
/// Output frames - the implementation.
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index ad3cf5e..d8d8742 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -2475,7 +2475,7 @@ void RtfAttributeOutput::CharHighlight(const SvxBrushItem& rBrush)
if (!rBrush.GetColor().GetTransparency())
{
m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HIGHLIGHT);
m_aStyles.append((sal_Int32)m_rExport.GetColor(rBrush.GetColor()));
m_aStyles.append(static_cast<sal_Int32>(msfilter::util::TransColToIco(rBrush.GetColor())));
}
}
diff --git a/sw/source/filter/ww8/rtfexport.cxx b/sw/source/filter/ww8/rtfexport.cxx
index 8b1ae6d..8130678 100644
--- a/sw/source/filter/ww8/rtfexport.cxx
+++ b/sw/source/filter/ww8/rtfexport.cxx
@@ -931,6 +931,7 @@ void RtfExport::InsColorLine(const SvxBoxItem& rBox)
if (rBox.GetRight() && pLine != rBox.GetRight())
InsColor(rBox.GetRight()->GetColor());
}
void RtfExport::OutColorTable()
{
// Build the table from rPool since the colors provided to
@@ -938,6 +939,24 @@ void RtfExport::OutColorTable()
sal_uInt32 nMaxItem;
const SfxItemPool& rPool = pDoc->GetAttrPool();
// MSO Word uses a default color table with 16 colors (which is used e.g. for highlighting)
InsColor(COL_BLACK);
InsColor(COL_LIGHTBLUE);
InsColor(COL_LIGHTCYAN);
InsColor(COL_LIGHTGREEN);
InsColor(COL_LIGHTMAGENTA);
InsColor(COL_LIGHTRED);
InsColor(COL_YELLOW);
InsColor(COL_WHITE);
InsColor(COL_BLUE);
InsColor(COL_CYAN);
InsColor(COL_GREEN);
InsColor(COL_MAGENTA);
InsColor(COL_RED);
InsColor(COL_BROWN);
InsColor(COL_GRAY);
InsColor(COL_LIGHTGRAY);
// char color
{
const SvxColorItem* pCol = static_cast<const SvxColorItem*>(GetDfltAttr(RES_CHRATR_COLOR));
@@ -976,7 +995,7 @@ void RtfExport::OutColorTable()
// background color
static const sal_uInt16 aBrushIds[] =
{
RES_BACKGROUND, RES_CHRATR_BACKGROUND, RES_CHRATR_HIGHLIGHT, 0
RES_BACKGROUND, RES_CHRATR_BACKGROUND, 0
};
for (const sal_uInt16* pIds = aBrushIds; *pIds; ++pIds)
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index ca6e5e1..b61b8da 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3471,7 +3471,6 @@ MSWordExportBase::MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM
, mpTopNodeOfHdFtPage(0)
, pBkmks(0)
, pRedlAuthors(0)
, pBmpPal(0)
, pOLEExp(0)
, pOCXExp(0)
, mpTableInfo(new ww8::WW8TableInfo())
@@ -3539,7 +3538,6 @@ MSWordExportBase::MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM
MSWordExportBase::~MSWordExportBase()
{
delete pBmpPal;
delete pOLEExp;
delete pOCXExp;
}
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index ee318b6..bc0c12f 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -463,7 +463,6 @@ public:
std::stack< sal_Int32 > m_aCurrentCharPropStarts; ///< To remember the position in a run.
WW8_WrtBookmarks* pBkmks;
WW8_WrtRedlineAuthor* pRedlAuthors;
BitmapPalette* pBmpPal;
boost::shared_ptr<NfKeywordTable> pKeyMap;
SvxMSExportOLEObjects* pOLEExp;
SwMSConvertControls* pOCXExp;
@@ -1096,7 +1095,6 @@ public:
void Out_SwFmtTableBox( ww::bytes& rO, const SvxBoxItem * rBox );
void Out_CellRangeBorders(const SvxBoxItem * pBox, sal_uInt8 nStart,
sal_uInt8 nLimit);
sal_uInt8 TransCol( const Color& rCol );
bool TransBrush(const Color& rCol, WW8_SHD& rShd);
WW8_BRCVer9 TranslateBorderLine(const ::editeng::SvxBorderLine& pLine,
sal_uInt16 nDist, bool bShadow);
diff --git a/sw/source/filter/ww8/wrtww8gr.cxx b/sw/source/filter/ww8/wrtww8gr.cxx
index eb1a1c5..1bb47ec 100644
--- a/sw/source/filter/ww8/wrtww8gr.cxx
+++ b/sw/source/filter/ww8/wrtww8gr.cxx
@@ -584,7 +584,7 @@ void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly,
{
WW8_BRCVer9 aBrc90 = rWrt.TranslateBorderLine( *pLn,
pBox->GetDistance( aLnArr[ i ] ), bShadow );
sal_uInt8 ico = rWrt.TransCol(msfilter::util::BGRToRGB(
sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
aBrc90.cv()));
aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 6e77450..70283f27 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -1286,7 +1286,7 @@ void WW8AttributeOutput::CharHighlight( const SvxBrushItem& rBrush )
{
if( m_rWW8Export.bWrtWW8 && rBrush.GetColor() != COL_TRANSPARENT )
{
sal_uInt8 nColor = m_rWW8Export.TransCol( rBrush.GetColor() );
sal_uInt8 nColor = msfilter::util::TransColToIco( rBrush.GetColor() );
// sprmCHighlight
m_rWW8Export.InsUInt16( NS_sprm::LN_CHighlight );
m_rWW8Export.pO->push_back( nColor );
@@ -1605,54 +1605,6 @@ void WW8AttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisM
}
}
// TransCol uebersetzt SW-Farben in WW. Heraus kommt die bei WW fuer
// Text- und Hintergrundfarbe benutzte Codierung.
// Gibt es keine direkte Entsprechung, dann wird versucht, eine moeglichst
// aehnliche WW-Farbe zu finden.
// return: 5-Bit-Wert ( 0..16 )
sal_uInt8 WW8Export::TransCol( const Color& rCol )
{
sal_uInt8 nCol = 0; // ->Auto
switch( rCol.GetColor() )
{
case COL_BLACK: nCol = 1; break;
case COL_BLUE: nCol = 9; break;
case COL_GREEN: nCol = 11; break;
case COL_CYAN: nCol = 10; break;
case COL_RED: nCol = 13; break;
case COL_MAGENTA: nCol = 12; break;
case COL_BROWN: nCol = 14; break;
case COL_GRAY: nCol = 15; break;
case COL_LIGHTGRAY: nCol = 16; break;
case COL_LIGHTBLUE: nCol = 2; break;
case COL_LIGHTGREEN: nCol = 4; break;
case COL_LIGHTCYAN: nCol = 3; break;
case COL_LIGHTRED: nCol = 6; break;
case COL_LIGHTMAGENTA: nCol = 5; break;
case COL_YELLOW: nCol = 7; break;
case COL_WHITE: nCol = 8; break;
case COL_AUTO: nCol = 0; break;
default:
if( !pBmpPal )
{
pBmpPal = new BitmapPalette( 16 );
static const ColorData aColArr[ 16 ] = {
COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
COL_LIGHTMAGENTA,COL_LIGHTRED, COL_YELLOW, COL_WHITE,
COL_BLUE, COL_CYAN, COL_GREEN, COL_MAGENTA,
COL_RED, COL_BROWN, COL_GRAY, COL_LIGHTGRAY
};
for( sal_uInt16 i = 0; i < 16; ++i )
pBmpPal->operator[]( i ) = Color( aColArr[ i ] );
}
nCol = static_cast< sal_uInt8 >(pBmpPal->GetBestIndex( rCol ) + 1);
break;
}
return nCol;
}
// TransBrush uebersetzt SW-Brushes in WW. Heraus kommt WW8_SHD.
// Nicht-Standardfarben des SW werden noch nicht in die
// Misch-Werte ( 0 .. 95% ) vom WW uebersetzt.
@@ -1666,7 +1618,7 @@ bool WW8Export::TransBrush(const Color& rCol, WW8_SHD& rShd)
else
{
rShd.SetFore( 0);
rShd.SetBack( TransCol( rCol ) );
rShd.SetBack( msfilter::util::TransColToIco( rCol ) );
rShd.SetStyle( bWrtWW8, 0 );
}
return !rCol.GetTransparency();
@@ -1686,7 +1638,7 @@ void WW8AttributeOutput::CharColor( const SvxColorItem& rColor )
else
m_rWW8Export.pO->push_back( 98 );
sal_uInt8 nColor = m_rWW8Export.TransCol( rColor.GetValue() );
sal_uInt8 nColor = msfilter::util::TransColToIco( rColor.GetValue() );
m_rWW8Export.pO->push_back( nColor );
if ( m_rWW8Export.bWrtWW8 && nColor )
@@ -4388,7 +4340,7 @@ void WW8Export::Out_BorderLine(ww::bytes& rO, const SvxBorderLine* pLine,
if( pLine && pLine->GetBorderLineStyle() != table::BorderLineStyle::NONE )
{
aBrcVer9 = TranslateBorderLine( *pLine, nDist, bShadow );
sal_uInt8 ico = TransCol( msfilter::util::BGRToRGB(aBrcVer9.cv()) );
sal_uInt8 ico = msfilter::util::TransColToIco( msfilter::util::BGRToRGB(aBrcVer9.cv()) );
aBrcVer8 = WW8_BRC( aBrcVer9.dptLineWidth(), aBrcVer9.brcType(), ico,
aBrcVer9.dptSpace(), aBrcVer9.fShadow(), aBrcVer9.fFrame() );
}