ooo-build r14430 - in trunk: . patches/dev300
- From: kyoshida svn gnome org
- To: svn-commits-list gnome org
- Subject: ooo-build r14430 - in trunk: . patches/dev300
- Date: Wed, 29 Oct 2008 20:21:38 +0000 (UTC)
Author: kyoshida
Date: Wed Oct 29 20:21:37 2008
New Revision: 14430
URL: http://svn.gnome.org/viewvc/ooo-build?rev=14430&view=rev
Log:
2008-10-29 Kohei Yoshida <kyoshida novell com>
* patches/dev300/calc-formula-asian-phonetic.diff: support PHONETIC
function that displays Asian phonetic guide from Japanese strings.
Adopted from patch written by Hiroyoki Ikezoe (ikezoe clear-code com)
as part of the Japanese Seagull Development Project 2007 (i#80764,
i#80765, i#80766).
* patches/dev300/apply: apply this new patch in CalcExperimental. This
patch is disabled by default.
Added:
trunk/patches/dev300/calc-formula-asian-phonetic.diff
Modified:
trunk/ChangeLog
trunk/patches/dev300/apply
Modified: trunk/patches/dev300/apply
==============================================================================
--- trunk/patches/dev300/apply (original)
+++ trunk/patches/dev300/apply Wed Oct 29 20:21:37 2008
@@ -1833,6 +1833,9 @@
# faster file load.
calc-xls-disable-adjust-row-height.diff, kohei
+# Support PHONETIC function to display asian phonetic guide.
+calc-formula-asian-phonetic.diff, i#80764, i#80765, i#80766, kohei
+
[ CalcSolver ]
SectionOwner => kohei
Added: trunk/patches/dev300/calc-formula-asian-phonetic.diff
==============================================================================
--- (empty file)
+++ trunk/patches/dev300/calc-formula-asian-phonetic.diff Wed Oct 29 20:21:37 2008
@@ -0,0 +1,2776 @@
+diff --git sc/inc/cell.hxx sc/inc/cell.hxx
+index a5aa3cf..816104c 100644
+--- sc/inc/cell.hxx
++++ sc/inc/cell.hxx
+@@ -43,6 +43,7 @@
+ #include "tokenarray.hxx"
+ #include "grammar.hxx"
+ #include "formularesult.hxx"
++#include "phonetic.hxx"
+ #include <rtl/ustrbuf.hxx>
+ #include <vcl/fontcvt.hxx>
+
+@@ -62,6 +63,7 @@ class ScTokenArray;
+ class ScProgress;
+ class ScPostIt;
+ class ScPatternAttr;
++class ScPhonetic;
+
+ class ScMultipleReadHeader;
+ class ScMultipleWriteHeader;
+@@ -169,6 +171,69 @@ public:
+
+ void SetString( const String& rString );
+ void GetString( String& rString ) const;
++
++ virtual bool HasPhonetic() const;
++};
++
++/**
++ * A class for representing of Asian phonetic guide.
++ */
++class ScAsianStringCell : public ScStringCell
++{
++private:
++ ScPhonetic aPhonetic;
++
++public:
++
++#ifdef USE_MEMPOOL
++ DECL_FIXEDMEMPOOL_NEWDEL( ScAsianStringCell )
++#endif
++#ifdef DBG_UTIL
++ ~ScAsianStringCell();
++#endif
++
++ ScAsianStringCell();
++
++ /**
++ * A constructor of ScAsianStringCell
++ * @param rString the text of the cell.
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ ScAsianStringCell( const String& rString, const ScPhonetic& rPhonetic );
++
++ /**
++ * A constructor of ScAsianStringCell
++ * @param rAsianStringCell a reference of ScAsianStringCell.
++ * @param pDoc a pointer of ScDocument.
++ */
++ ScAsianStringCell( const ScAsianStringCell& rScAsianStringCell, ScDocument* pDoc );
++
++ /**
++ * A constructor of ScAsianStringCell
++ * @param rStream a reference of SvStream.
++ * @param nVer the number of vesion.
++ */
++ ScAsianStringCell( SvStream& rStream, USHORT nVer );
++
++ /**
++ * Creates a new ScAsianStringCell.
++ * @return a pointer of the ScBaseCell.
++ */
++ ScBaseCell* Clone(ScDocument* pDoc) const;
++
++ /**
++ * Sets ScPhonetic:
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ void SetPhonetic( const ScPhonetic& rPhonetic );
++
++ /**
++ * Gets ScPhonetic:
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ void GetPhonetic( ScPhonetic& rPhonetic ) const;
++
++ virtual bool HasPhonetic() const;
+ };
+
+
+@@ -206,6 +271,8 @@ public:
+ void GetData( const EditTextObject*& rpObject ) const;
+ void GetString( String& rString ) const;
+
++ virtual bool HasPhonetic() const;
++
+ const EditTextObject* GetData() const { return pData; }
+
+ /** Removes character attribute based on new pattern attributes. */
+@@ -258,6 +325,73 @@ private:
+
+ // ----------------------------------------------------------------------------
+
++
++/**
++ * A class for representing of Asian phonetic guide.
++ * It is derived from ScStringCell.
++ */
++class ScAsianEditCell : public ScEditCell
++{
++private:
++ ScPhonetic aPhonetic;
++
++public:
++
++#ifdef USE_MEMPOOL
++ DECL_FIXEDMEMPOOL_NEWDEL( ScAsianStringCell )
++#endif
++#ifdef DBG_UTIL
++ ~ScAsianEditCell();
++#endif
++
++ /**
++ * A constructor of ScAsianEditCell
++ * @param rEditCell a reference of SCAsianEditCell.
++ * @param pDoc a pointer of ScDocument.
++ */
++ ScAsianEditCell( const ScAsianEditCell& rEditCell, ScDocument* pDoc );
++
++ /**
++ * A constructor of ScAsianEditCell
++ * @param rEditCell a reference of ScEditCell.
++ * @param pDoc a pointer of ScDocument.
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ ScAsianEditCell( const ScEditCell& rEditCell, ScDocument *pDoc, const ScPhonetic& rPhonetic );
++
++ /**
++ * A constructor of ScAsianEditCell
++ * @param pObject a pointer of EditTextObject.
++ * @param pDoc a pointer of ScDocument.
++ * @param pFromPool a pointer of SfxItemPool.
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ ScAsianEditCell( const EditTextObject* pObject, ScDocument* pDoc,
++ const SfxItemPool* pFromPool, const ScPhonetic& rPhonetic );
++
++ /**
++ * Creates a new ScAsianStringCell.
++ * @return a pointer of the ScBaseCell.
++ */
++ ScBaseCell* Clone(ScDocument* pDoc) const;
++
++ /**
++ * Sets ScPhonetic:
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ void SetPhonetic( const ScPhonetic& rPhonetic );
++
++ /**
++ * Gets ScPhonetic:
++ * @param rPhonetic a reference of ScPhonetic.
++ */
++ void GetPhonetic( ScPhonetic& rPhonetic ) const;
++
++ virtual bool HasPhonetic() const;
++};
++
++// ----------------------------------------------------------------------------
++
+ enum ScMatrixMode {
+ MM_NONE = 0, // No matrix formula
+ MM_FORMULA = 1, // Upper left matrix formula cell
+@@ -589,6 +723,91 @@ inline void ScStringCell::SetString( const String& rString )
+ aString = rString;
+ }
+
++inline bool ScStringCell::HasPhonetic() const
++{
++ return false;
++}
++
++// ScAsianStringCell
++
++inline ScAsianStringCell::ScAsianStringCell() :
++ ScStringCell( CELLTYPE_STRING )
++{
++}
++
++inline ScAsianStringCell::ScAsianStringCell( const ScAsianStringCell& rScAsianStringCell, ScDocument* pDoc ) :
++ ScStringCell( rScAsianStringCell, pDoc ),
++ aPhonetic ( rScAsianStringCell.aPhonetic )
++{
++}
++
++inline ScAsianStringCell::ScAsianStringCell( const String& rString, const ScPhonetic& rPhonetic ) :
++ ScStringCell ( rString ),
++ aPhonetic ( rPhonetic )
++{
++}
++
++inline ScBaseCell* ScAsianStringCell::Clone(ScDocument* pDoc) const
++{
++ return new ScAsianStringCell(*this, pDoc);
++}
++
++inline void ScAsianStringCell::GetPhonetic( ScPhonetic& rPhonetic ) const
++{
++ rPhonetic = aPhonetic;
++}
++
++inline bool ScAsianStringCell::HasPhonetic() const
++{
++ return true;
++}
++
++inline void ScAsianStringCell::SetPhonetic( const ScPhonetic& rPhonetic )
++{
++ aPhonetic = rPhonetic;
++}
++
++// ScAsianEditCell
++
++inline ScAsianEditCell::ScAsianEditCell( const ScAsianEditCell& rEditCell, ScDocument* pDocP) :
++ ScEditCell( (const ScEditCell&)rEditCell, pDocP ),
++ aPhonetic( rEditCell.aPhonetic )
++{
++}
++
++inline ScAsianEditCell::ScAsianEditCell( const ScEditCell& rEditCell, ScDocument* pDocP, const ScPhonetic& rPhonetic ) :
++ ScEditCell( rEditCell, pDocP ),
++ aPhonetic( rPhonetic )
++{
++}
++
++inline ScAsianEditCell::ScAsianEditCell( const EditTextObject* pObject, ScDocument* pDocP,
++ const SfxItemPool* pFromPool, const ScPhonetic& rPhonetic ) :
++ ScEditCell( pObject, pDocP, pFromPool ),
++ aPhonetic( rPhonetic )
++{
++}
++
++inline ScBaseCell* ScAsianEditCell::Clone(ScDocument* pDocP) const
++{
++ return new ScAsianEditCell(*this, pDocP);
++}
++
++inline void ScAsianEditCell::GetPhonetic( ScPhonetic& rPhonetic ) const
++{
++ rPhonetic = aPhonetic;
++}
++
++inline void ScAsianEditCell::SetPhonetic( const ScPhonetic& rPhonetic )
++{
++ aPhonetic = rPhonetic;
++}
++
++inline bool ScAsianEditCell::HasPhonetic() const
++{
++ return true;
++}
++
+
+ /*
+
+diff --git sc/inc/cellsuno.hxx sc/inc/cellsuno.hxx
+index 99b32c4..e89bd77 100644
+--- sc/inc/cellsuno.hxx
++++ sc/inc/cellsuno.hxx
+@@ -976,6 +976,14 @@ public:
+
+ static String GetInputString_Impl(ScDocument* pDoc, const ScAddress& aPos, BOOL bEnglish);
+ static String GetOutputString_Impl(ScDocument* pDoc, const ScAddress& aPos);
++
++ /**
++ * Gets phonetic text from a cell.
++ *
++ * @param pDoc A pointer of ScDocument.
++ * @param aPos A reference of ScAdress.
++ */
++ static String GetOutputPhoneticString_Impl(ScDocument* pDoc, const ScAddress& aPos);
+ };
+
+
+diff --git sc/inc/compiler.hrc sc/inc/compiler.hrc
+index ec67599..a8a9d78 100644
+--- sc/inc/compiler.hrc
++++ sc/inc/compiler.hrc
+@@ -192,7 +192,8 @@
+ #define SC_OPCODE_ASC 154
+ #define SC_OPCODE_UNICODE 155
+ #define SC_OPCODE_UNICHAR 156
+-#define SC_OPCODE_STOP_1_PAR 157
++#define SC_OPCODE_PHONETIC 157
++#define SC_OPCODE_STOP_1_PAR 158
+
+ /*** Functions with more than one parameters ***/
+ #define SC_OPCODE_START_2_PAR 201
+diff --git sc/inc/opcode.hxx sc/inc/opcode.hxx
+index e0940f7..a98fb5b 100644
+--- sc/inc/opcode.hxx
++++ sc/inc/opcode.hxx
+@@ -187,6 +187,7 @@ enum OpCodeEnum
+ ocAsc = SC_OPCODE_ASC,
+ ocUnicode = SC_OPCODE_UNICODE,
+ ocUnichar = SC_OPCODE_UNICHAR,
++ ocPhonetic = SC_OPCODE_PHONETIC,
+ // Functions with more than one parameters
+ ocArcTan2 = SC_OPCODE_ARC_TAN_2,
+ ocCeil = SC_OPCODE_CEIL,
+diff --git sc/inc/phonetic.hxx sc/inc/phonetic.hxx
+new file mode 100644
+index 0000000..9a369d8
+--- /dev/null
++++ sc/inc/phonetic.hxx
+@@ -0,0 +1,107 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: global.hxx,v $
++ * $Revision: 1.53 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org. If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef SC_PHONETIC_HXX
++#define SC_PHONETIC_HXX
++
++#include <vector>
++
++#ifndef _STRING_HXX
++#include <tools/string.hxx>
++#endif
++
++struct PhoneticPortion
++{
++ sal_uInt16 mncpa; /// position of the first character in the phonetic text
++ sal_uInt16 mncpm; /// position of the first character in the base text
++ sal_uInt16 mnccm; /// length of the characters in the base text
++ explicit inline PhoneticPortion() : mncpa( 0 ), mncpm( 0 ), mnccm( 0 ) {}
++ explicit inline PhoneticPortion( sal_uInt16 ncpa, sal_uInt16 ncpm, sal_uInt16 nccm ) :
++ mncpa( ncpa ), mncpm( ncpm ), mnccm ( nccm ) {}
++};
++
++inline bool operator==( const PhoneticPortion& rLeft, const PhoneticPortion& rRight )
++{
++ return
++ ( rLeft.mncpa == rRight.mncpa ) &&
++ ( rLeft.mncpm == rRight.mncpm ) &&
++ ( rLeft.mnccm == rRight.mnccm );
++}
++
++typedef ::std::vector< PhoneticPortion > PhoneticPortionVec;
++
++/*
++ * A class for store Asian phonetic guide information.
++ */
++class ScPhonetic
++{
++public:
++ ScPhonetic() : mnFontIdx( 0 ), mnAdditionalSettings( 0 ), mnRepeatedTotalLength ( 0 ) {}
++ /** A constructor of ScPhonetic.
++ * @param nFontIdx font index.
++ * @param nAdditionalSettings an additional settings.
++ * @param nRepeatedTotalLength the number of repeated total length.
++ * @param rPhoneticString phonetic text.
++ * @param rPhoneticPortions the portion of phonetic text.
++ */
++ ScPhonetic( sal_uInt16 nFontIdx, sal_uInt16 nAdditionalSettings,
++ sal_uInt16 nRepeatedTotalLength, const String& rPhoneticString,
++ const PhoneticPortionVec& rPhoneticPortions) :
++ mnFontIdx( nFontIdx ), mnAdditionalSettings( nAdditionalSettings ),
++ mnRepeatedTotalLength ( nRepeatedTotalLength ),
++ maPhoneticString ( rPhoneticString ), maPhoneticPortions ( rPhoneticPortions ) {}
++ virtual ~ScPhonetic();
++
++ virtual int operator==( const ScPhonetic& ) const;
++
++ /** Returns True if no phonetic information. */
++ inline BOOL IsEmpty() const { return maPhoneticString.Len() == 0; }
++ /** Returns the text for phonetic information. */
++ inline const String& GetString() const { return maPhoneticString; }
++ /** Returns the portion for phonetic information. */
++ inline const PhoneticPortionVec& GetPortions() const { return maPhoneticPortions; }
++ /** Returns font index of phonetic information. */
++ inline sal_uInt16 GetFontIndex() const { return mnFontIdx; }
++ /** Returns additional settings of phonetic information. */
++ inline sal_uInt16 GetAdditionalSettings() const { return mnAdditionalSettings; }
++ /** Returns repeated length of phonetic information. */
++ inline sal_uInt16 GetRepeatedTotalLength() const { return mnRepeatedTotalLength; }
++ /** Returns the size of phonetic information. */
++ inline sal_uInt32 GetSize() const { return 14 + ( maPhoneticString.Len() ? maPhoneticString.Len() * 2 : 2 ) + maPhoneticPortions.size() * 6; }
++
++private:
++ sal_uInt16 mnFontIdx; /// Index to FONT record
++ sal_uInt16 mnAdditionalSettings; /// Additional settings for the Asian phonetic text
++ sal_uInt16 mnRepeatedTotalLength;
++ String maPhoneticString;
++ PhoneticPortionVec maPhoneticPortions;
++};
++
++#endif
+diff --git sc/inc/scfuncs.hrc sc/inc/scfuncs.hrc
+index 37e62f6..5d34782 100644
+--- sc/inc/scfuncs.hrc
++++ sc/inc/scfuncs.hrc
+@@ -330,3 +330,4 @@
+ #define HID_FUNC_UNICODE (HID_SC_FUNC_DUMMY+(ID_FUNCTION_GRP_TEXT*ID_FUNCTION_OFFSET)+31)
+ #define HID_FUNC_UNICHAR (HID_SC_FUNC_DUMMY+(ID_FUNCTION_GRP_TEXT*ID_FUNCTION_OFFSET)+32)
+ #define HID_FUNC_NUMBERVALUE (HID_SC_FUNC_DUMMY+(ID_FUNCTION_GRP_TEXT*ID_FUNCTION_OFFSET)+33)
++#define HID_FUNC_PHONETIC (HID_SC_FUNC_DUMMY+(ID_FUNCTION_GRP_TEXT*ID_FUNCTION_OFFSET)+34)
+diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
+index c330826..df5e777 100644
+--- sc/source/core/data/cell.cxx
++++ sc/source/core/data/cell.cxx
+@@ -75,10 +75,14 @@ const USHORT nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell);
+ const USHORT nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell);
+ const USHORT nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell);
+ const USHORT nMemPoolNoteCell = (0x1000 - 64) / sizeof(ScNoteCell);
++const USHORT nMemPoolAsianStringCell = (0x4000 - 64) / sizeof(ScAsianStringCell);
++const USHORT nMemPoolAsianEditCell = (0x4000 - 64) / sizeof(ScAsianEditCell);
+ IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell, nMemPoolValueCell, nMemPoolValueCell )
+ IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell, nMemPoolFormulaCell, nMemPoolFormulaCell )
+ IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell )
+ IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell )
++IMPL_FIXEDMEMPOOL_NEWDEL( ScAsianStringCell, nMemPoolAsianStringCell, nMemPoolAsianStringCell )
++IMPL_FIXEDMEMPOOL_NEWDEL( ScAsianEditCell, nMemPoolAsianEditCell, nMemPoolAsianEditCell )
+ #endif
+
+ #ifndef PRODUCT
+@@ -483,19 +487,31 @@ BOOL ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 )
+ return ( ((const ScValueCell*)pCell1)->GetValue() ==
+ ((const ScValueCell*)pCell2)->GetValue() );
+ case CELLTYPE_STRING: // String oder Edit
+- {
+- String aText1;
+- if ( pCell1->GetCellType() == CELLTYPE_STRING )
+- ((const ScStringCell*)pCell1)->GetString(aText1);
+- else
+- ((const ScEditCell*)pCell1)->GetString(aText1);
+- String aText2;
+- if ( pCell2->GetCellType() == CELLTYPE_STRING )
+- ((const ScStringCell*)pCell2)->GetString(aText2);
+- else
+- ((const ScEditCell*)pCell2)->GetString(aText2);
+- return ( aText1 == aText2 );
+- }
++ {
++ String aText1, aText2;
++ const ScStringCell* pStrCell1 = static_cast<const ScStringCell*>(pCell1);
++ const ScStringCell* pStrCell2 = static_cast<const ScStringCell*>(pCell2);
++ pStrCell1->GetString( aText1 );
++ pStrCell2->GetString( aText2 );
++ if (aText1 != aText2)
++ return false;
++
++ ScPhonetic aPhonetic1, aPhonetic2;
++ if (pStrCell1->HasPhonetic())
++ {
++ const ScAsianStringCell* pPhoCell1 =
++ static_cast<const ScAsianStringCell*>(pStrCell1);
++ pPhoCell1->GetPhonetic(aPhonetic1);
++ }
++ if (pStrCell2->HasPhonetic())
++ {
++ const ScAsianStringCell* pPhoCell2 =
++ static_cast<const ScAsianStringCell*>(pStrCell2);
++ pPhoCell2->GetPhonetic(aPhonetic2);
++ }
++
++ return aPhonetic1 == aPhonetic2;
++ }
+ case CELLTYPE_FORMULA:
+ {
+ //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!!
+diff --git sc/source/core/data/cell2.cxx sc/source/core/data/cell2.cxx
+index f770a60..91dd93a 100644
+--- sc/source/core/data/cell2.cxx
++++ sc/source/core/data/cell2.cxx
+@@ -143,6 +143,11 @@ void ScEditCell::GetString( String& rString ) const
+ rString.Erase();
+ }
+
++bool ScEditCell::HasPhonetic() const
++{
++ return false;
++}
++
+ void ScEditCell::RemoveCharAttribs( const ScPatternAttr& rAttr )
+ {
+ const struct {
+diff --git sc/source/core/data/makefile.mk sc/source/core/data/makefile.mk
+index 1cad27e..b6c8269 100644
+--- sc/source/core/data/makefile.mk
++++ sc/source/core/data/makefile.mk
+@@ -97,6 +97,7 @@ SLOFILES = \
+ $(SLO)$/patattr.obj \
+ $(SLO)$/pivot.obj \
+ $(SLO)$/pivot2.obj \
++ $(SLO)$/phonetic.obj \
+ $(SLO)$/poolhelp.obj \
+ $(SLO)$/scimpexpmsg.obj \
+ $(SLO)$/sortparam.obj \
+diff --git sc/source/core/data/phonetic.cxx sc/source/core/data/phonetic.cxx
+new file mode 100644
+index 0000000..1bd10fa
+--- /dev/null
++++ sc/source/core/data/phonetic.cxx
+@@ -0,0 +1,72 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: global.hxx,v $
++ * $Revision: 1.53 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org. If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++// INCLUDE ---------------------------------------------------------------
++
++#if 1
++#ifndef _COM_SUN_STAR_UTIL_CELLPROTECTION_HPP_
++#include <com/sun/star/util/CellProtection.hpp>
++#endif
++#ifndef _COM_SUN_STAR_UTIL_XPROTECTABLE_HPP_
++#include <com/sun/star/util/XProtectable.hpp>
++#endif
++#ifndef _COM_SUN_STAR_TEXT_XTEXT_HPP_
++#include <com/sun/star/text/XText.hpp>
++#endif
++#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
++#include <com/sun/star/beans/XPropertySet.hpp>
++#endif
++#endif
++
++#include "phonetic.hxx"
++
++using namespace com::sun::star;
++
++
++//------------------------------------------------------------------------
++
++ScPhonetic::~ScPhonetic()
++{
++}
++
++//------------------------------------------------------------------------
++
++int ScPhonetic::operator==( const ScPhonetic& rItem ) const
++{
++ return ((mnFontIdx == rItem.mnFontIdx)
++ && (mnAdditionalSettings == rItem.mnAdditionalSettings)
++ && (mnRepeatedTotalLength == rItem.mnRepeatedTotalLength)
++ && (maPhoneticString == rItem.maPhoneticString)
++ && (maPhoneticPortions == rItem.maPhoneticPortions));
++}
++
+diff --git sc/source/core/inc/interpre.hxx sc/source/core/inc/interpre.hxx
+index f9c5df5..ae73a6f 100644
+--- sc/source/core/inc/interpre.hxx
++++ sc/source/core/inc/interpre.hxx
+@@ -179,6 +179,7 @@ double GetValueCellValue( const ScAddress&, const ScValueCell* );
+ ScBaseCell* GetCell( const ScAddress& rPos )
+ { return pDok->GetCell( rPos ); }
+ void GetCellString( String& rStr, const ScBaseCell* pCell );
++void GetCellPhoneticString( String& rStr, const ScBaseCell* pCell );
+ inline USHORT GetCellErrCode( const ScBaseCell* pCell )
+ { return pCell ? pCell->GetErrorCode() : 0; }
+ inline CellType GetCellType( const ScBaseCell* pCell )
+@@ -508,6 +509,7 @@ void ScExternalRef();
+ void ScGetPivotData();
+ void ScHyperLink();
+ void ScBahtText();
++void ScPhoneticString();
+ void ScCalcTeam();
+ void ScAnswer();
+ void ScTTT();
+diff --git sc/source/core/src/compiler.src sc/source/core/src/compiler.src
+index adf9402..579f2f8 100644
+--- sc/source/core/src/compiler.src
++++ sc/source/core/src/compiler.src
+@@ -1167,6 +1167,10 @@ Resource RID_SC_FUNCTION_NAMES
+ {
+ Text [ en-US ] = "BAHTTEXT";
+ };
++ String SC_OPCODE_PHONETIC
++ {
++ Text [ en-US ] = "PHONETIC";
++ };
+ String SC_OPCODE_GET_PIVOT_DATA
+ {
+ Text [ en-US ] = "GETPIVOTDATA";
+@@ -1526,6 +1530,7 @@ Resource RID_SC_FUNCTION_NAMES_ENGLISH
+ String SC_OPCODE_HYPERLINK { Text = "HYPERLINK" ; };
+ String SC_OPCODE_INFO { Text = "INFO" ; };
+ String SC_OPCODE_BAHTTEXT { Text = "BAHTTEXT" ; };
++ String SC_OPCODE_PHONETIC { Text = "PHONETIC" ; };
+ String SC_OPCODE_GET_PIVOT_DATA { Text = "GETPIVOTDATA" ; };
+ String SC_OPCODE_EUROCONVERT { Text = "EUROCONVERT" ; };
+ String SC_OPCODE_NUMBERVALUE { Text = "NUMBERVALUE" ; };
+@@ -1847,6 +1852,7 @@ Resource RID_SC_FUNCTION_NAMES_ENGLISH_ODFF
+ String SC_OPCODE_HYPERLINK { Text = "HYPERLINK" ; };
+ String SC_OPCODE_INFO { Text = "INFO" ; };
+ String SC_OPCODE_BAHTTEXT { Text = "COM.MICROSOFT.BAHTTEXT" ; };
++ String SC_OPCODE_PHONETIC { Text = "PHONETIC" ; };
+ String SC_OPCODE_GET_PIVOT_DATA { Text = "GETPIVOTDATA" ; };
+ String SC_OPCODE_EUROCONVERT { Text = "EUROCONVERT" ; };
+ String SC_OPCODE_NUMBERVALUE { Text = "NUMBERVALUE" ; };
+diff --git sc/source/core/tool/interpr2.cxx sc/source/core/tool/interpr2.cxx
+index 17ee3a4..30bf04b 100644
+--- sc/source/core/tool/interpr2.cxx
++++ sc/source/core/tool/interpr2.cxx
+@@ -2667,6 +2667,76 @@ void ScInterpreter::ScBahtText()
+
+ // ============================================================================
+
++void ScInterpreter::ScPhoneticString()
++{
++ BYTE nParamCount = GetByte();
++ if ( MustHaveParamCountMin( nParamCount, 1 ) )
++ {
++ String aPhoneticText;
++ while( nParamCount-- )
++ {
++ if ( nGlobalError )
++ {
++ PushError(nGlobalError);
++ return;
++ }
++
++ switch ( GetStackType() )
++ {
++ case svSingleRef :
++ {
++ ScAddress aAdr;
++ PopSingleRef( aAdr );
++ if (nGlobalError)
++ {
++ PushError(nGlobalError);
++ return;
++ }
++
++ ScBaseCell* pCell = GetCell( aAdr );
++ if ( HasCellStringData( pCell ) )
++ {
++ String aStr;
++ GetCellPhoneticString( aStr, pCell );
++ aPhoneticText += aStr;
++ }
++ }
++ break;
++ case svDoubleRef:
++ {
++ ScRange aRange;
++ PopDoubleRef( aRange );
++ if (nGlobalError)
++ {
++ PushError(nGlobalError);
++ return;
++ }
++
++ ScCellIterator aIter( pDok, aRange );
++ ScBaseCell *pCell = aIter.GetFirst();
++ while ( pCell )
++ {
++ if ( HasCellStringData( pCell ) )
++ {
++ String aStr;
++ GetCellPhoneticString( aStr, pCell );
++ aPhoneticText += aStr;
++ }
++ pCell = aIter.GetNext();
++ }
++ }
++ break;
++ default:
++ PushError(errIllegalParameter);
++ return;
++ }
++ }
++ PushString( aPhoneticText );
++ }
++}
++
++// ============================================================================
++
+ void ScInterpreter::ScGetPivotData()
+ {
+ BYTE nParamCount = GetByte();
+diff --git sc/source/core/tool/interpr4.cxx sc/source/core/tool/interpr4.cxx
+index 9350576..64359c8 100644
+--- sc/source/core/tool/interpr4.cxx
++++ sc/source/core/tool/interpr4.cxx
+@@ -341,6 +341,189 @@ void ScInterpreter::GetCellString( String& rStr, const ScBaseCell* pCell )
+ SetError(nErr);
+ }
+
++static sal_Bool lcl_IsHalfWidthKatakana ( const String& rString )
++{
++ sal_Int32 nLen = rString.Len();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( rString.GetChar(i) < 0xFF00 || rString.GetChar(i) > 0xFFEF )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_Bool lcl_IsFullWidthKatakana ( const String& rString )
++{
++ sal_Int32 nLen = rString.Len();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( rString.GetChar(i) < 0x30A0 || rString.GetChar(i) > 0x30FF )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_Bool lcl_IsFullWidthHiragana ( const String& rString )
++{
++ sal_Int32 nLen = rString.Len();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( rString.GetChar(i) < 0x3040 || rString.GetChar(i) > 0x309F )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_uInt16 lcl_GetKanaType ( const String rText )
++{
++ sal_uInt16 aKanaType = 0;
++
++ if ( lcl_IsHalfWidthKatakana ( rText ) )
++ aKanaType = 0x00;
++ else if ( lcl_IsFullWidthKatakana ( rText ) )
++ aKanaType = 0x01;
++ else if ( lcl_IsFullWidthHiragana ( rText ) )
++ aKanaType = 0x02;
++
++ return aKanaType;
++}
++
++static void lcl_ConvertToKatakana( ScDocument* pDoc, String& rStr )
++{
++ sal_uInt16 nKanaType = lcl_GetKanaType(rStr);
++ sal_Int32 nType = com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA;
++ switch (nKanaType)
++ {
++ case 0x00:
++ // half-width katakana or full-width alphabet.
++ nType = com::sun::star::i18n::TransliterationModules_HALFWIDTH_FULLWIDTH;
++ break;
++ case 0x02:
++ // full-width hiragana.
++ nType = com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA;
++ break;
++ case 0x01:
++ default:
++ // full-width katakana. no need to convert this.
++ return;
++ }
++ utl::TransliterationWrapper aTranslitarationWrapper( pDoc->GetServiceManager(), nType );
++ com::sun::star::uno::Sequence<sal_Int32> aOffsets;
++ rStr = aTranslitarationWrapper.transliterate( rStr, LANGUAGE_JAPANESE, 0, rStr.Len(), &aOffsets );
++}
++
++static void lcl_GetPhoneticString ( ScDocument *pDoc, String& rStr, const ScBaseCell* pCell )
++{
++ ScPhonetic aPhonetic;
++ String aBaseString;
++ switch (pCell->GetCellType())
++ {
++ case CELLTYPE_STRING:
++ static_cast<const ScStringCell*>(pCell)->GetString(aBaseString);
++ static_cast<const ScAsianStringCell*>(pCell)->GetPhonetic(aPhonetic);
++ break;
++ case CELLTYPE_EDIT:
++ static_cast<const ScEditCell*>(pCell)->GetString(aBaseString);
++ static_cast<const ScAsianEditCell*>(pCell)->GetPhonetic(aPhonetic);
++ break;
++ default:
++ // Not a supported cell type.
++ return;
++ }
++
++ if (aPhonetic.IsEmpty())
++ // No phonetic string exists. Bail out.
++ return;
++
++ const String& rPhoneticString = aPhonetic.GetString();
++ PhoneticPortionVec portions = aPhonetic.GetPortions();
++ sal_uInt16 nPortionCount = portions.size();
++
++ String tmpString;
++ if ( nPortionCount > 0 )
++ {
++ sal_uInt16 pos = 0;
++ for ( sal_uInt16 idx = 0; idx < nPortionCount; ++idx )
++ {
++ const PhoneticPortion& portion = portions[idx];
++
++ // Get the end position in the phonetic text.
++ sal_uInt16 nPhEndPos = idx < nPortionCount-1 ? portions[idx+1].mncpa : rPhoneticString.Len();
++
++ tmpString += aBaseString.Copy(pos, portion.mncpm - pos);
++ pos = portion.mncpm + portion.mnccm;
++ tmpString += rPhoneticString.Copy(portion.mncpa, nPhEndPos - portion.mncpa);
++ }
++ if ( pos < aBaseString.Len() )
++ tmpString += aBaseString.Copy(pos, aBaseString.Len() - pos);
++ }
++ else
++ {
++ tmpString = rPhoneticString;
++ }
++
++ sal_Int32 nType;
++ switch ( lcl_GetKanaType ( rPhoneticString ))
++ {
++ case 0x00:
++ nType = com::sun::star::i18n::TransliterationModules_FULLWIDTH_HALFWIDTH;
++ break;
++ case 0x01:
++ nType = com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA;
++ break;
++ case 0x02:
++ nType = com::sun::star::i18n::TransliterationModules_KATAKANA_HIRAGANA;
++ break;
++ default:
++ nType = com::sun::star::i18n::TransliterationModules_HIRAGANA_KATAKANA;
++ break;
++ }
++
++ utl::TransliterationWrapper aTranslitarationWrapper( pDoc->GetServiceManager(), nType );
++ com::sun::star::uno::Sequence<sal_Int32> aOffsets;
++ rStr = aTranslitarationWrapper.transliterate( tmpString, LANGUAGE_JAPANESE, 0, tmpString.Len(), &aOffsets );
++}
++
++void ScInterpreter::GetCellPhoneticString( String& rStr, const ScBaseCell* pCell )
++{
++ USHORT nErr = 0;
++ if ( pCell )
++ {
++ switch ( pCell->GetCellType() )
++ {
++ case CELLTYPE_STRING:
++ if ( static_cast<const ScStringCell*>(pCell)->HasPhonetic() )
++ lcl_GetPhoneticString(pDok, rStr, pCell);
++ else
++ {
++ static_cast<const ScStringCell*>(pCell)->GetString(rStr);
++ lcl_ConvertToKatakana(pDok, rStr);
++ }
++ break;
++ case CELLTYPE_EDIT:
++ if ( static_cast<const ScEditCell*>(pCell)->HasPhonetic() )
++ lcl_GetPhoneticString(pDok, rStr, pCell);
++ else
++ {
++ static_cast<const ScEditCell*>(pCell)->GetString(rStr);
++ lcl_ConvertToKatakana(pDok, rStr);
++ }
++ break;
++ default:
++ rStr = ScGlobal::GetEmptyString();
++ break;
++ }
++ }
++ else
++ rStr = ScGlobal::GetEmptyString();
++ SetError(nErr);
++}
+
+ BOOL ScInterpreter::CreateDoubleArr(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, BYTE* pCellArr)
+@@ -3779,6 +3962,7 @@ StackVar ScInterpreter::Interpret()
+ case ocInfo : ScInfo(); break;
+ case ocHyperLink : ScHyperLink(); break;
+ case ocBahtText : ScBahtText(); break;
++ case ocPhonetic : ScPhoneticString(); break;
+ case ocGetPivotData : ScGetPivotData(); break;
+ case ocJis : ScJis(); break;
+ case ocAsc : ScAsc(); break;
+diff --git sc/source/filter/excel/xehelper.cxx sc/source/filter/excel/xehelper.cxx
+index 37bab79..6159835 100644
+--- sc/source/filter/excel/xehelper.cxx
++++ sc/source/filter/excel/xehelper.cxx
+@@ -587,7 +587,16 @@ XclExpStringRef XclExpStringHelper::CreateCellString(
+ {
+ String aCellText;
+ rStringCell.GetString( aCellText );
+- return lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
++ XclExpStringRef xString = lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
++ if (rStringCell.HasPhonetic())
++ {
++ ScPhonetic aPhonetic;
++ static_cast<const ScAsianStringCell&>(rStringCell).GetPhonetic(aPhonetic);
++ if ( !aPhonetic.IsEmpty() )
++ xString->SetPhoneticSettings(aPhonetic);
++ }
++
++ return xString;
+ }
+
+ XclExpStringRef XclExpStringHelper::CreateCellString(
+@@ -618,6 +627,15 @@ XclExpStringRef XclExpStringHelper::CreateCellString(
+ rEditCell.GetString( aCellText );
+ xString = lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
+ }
++
++ if (rEditCell.HasPhonetic())
++ {
++ ScPhonetic aPhonetic;
++ static_cast<const ScAsianEditCell&>(rEditCell).GetPhonetic(aPhonetic);
++ if ( !aPhonetic.IsEmpty() )
++ xString->SetPhoneticSettings(aPhonetic);
++ }
++
+ return xString;
+ }
+
+diff --git sc/source/filter/excel/xestring.cxx sc/source/filter/excel/xestring.cxx
+index a367647..78bca3e 100644
+--- sc/source/filter/excel/xestring.cxx
++++ sc/source/filter/excel/xestring.cxx
+@@ -253,7 +253,8 @@ bool XclExpString::IsEqual( const XclExpString& rCmp ) const
+ ( mbIsBiff8 && (maUniBuffer == rCmp.maUniBuffer)) ||
+ (!mbIsBiff8 && (maCharBuffer == rCmp.maCharBuffer))
+ ) &&
+- (maFormats == rCmp.maFormats);
++ (maFormats == rCmp.maFormats) &&
++ (maPhonetic == rCmp.maPhonetic);
+ }
+
+ bool XclExpString::IsLessThan( const XclExpString& rCmp ) const
+@@ -264,6 +265,18 @@ bool XclExpString::IsLessThan( const XclExpString& rCmp ) const
+ return (nResult != 0) ? (nResult < 0) : (maFormats < rCmp.maFormats);
+ }
+
++bool XclExpString::HasPhonetic() const
++{
++ return !maPhonetic.IsEmpty();
++}
++
++// formatting runs ------------------------------------------------------------
++
++void XclExpString::SetPhoneticSettings( const ScPhonetic& rPhonetic )
++{
++ maPhonetic = rPhonetic;
++}
++
+ // get data -------------------------------------------------------------------
+
+ sal_uInt16 XclExpString::GetFormatsCount() const
+@@ -271,17 +284,25 @@ sal_uInt16 XclExpString::GetFormatsCount() const
+ return static_cast< sal_uInt16 >( maFormats.size() );
+ }
+
++sal_uInt32 XclExpString::GetPhoneticSettingsCount() const
++{
++ return maPhonetic.GetSize();
++}
++
+ sal_uInt8 XclExpString::GetFlagField() const
+ {
+- return (mbIsUnicode ? EXC_STRF_16BIT : 0) | (IsWriteFormats() ? EXC_STRF_RICH : 0);
++ return (mbIsUnicode ? EXC_STRF_16BIT : 0) |
++ (IsWritePhoneticSettings() ? EXC_STRF_FAREAST : 0 ) |
++ (IsWriteFormats() ? EXC_STRF_RICH : 0);
+ }
+
+ sal_uInt16 XclExpString::GetHeaderSize() const
+ {
+ return
+- (mb8BitLen ? 1 : 2) + // length field
+- (IsWriteFlags() ? 1 : 0) + // flag field
+- (IsWriteFormats() ? 2 : 0); // richtext formattting count
++ (mb8BitLen ? 1 : 2) + // length field
++ (IsWriteFlags() ? 1 : 0) + // flag field
++ (IsWriteFormats() ? 2 : 0) + // richtext formattting count
++ (IsWritePhoneticSettings() ? 4 : 0); // phonetic settings count
+ }
+
+ sal_Size XclExpString::GetBufferSize() const
+@@ -292,9 +313,10 @@ sal_Size XclExpString::GetBufferSize() const
+ sal_Size XclExpString::GetSize() const
+ {
+ return
+- GetHeaderSize() + // header
+- GetBufferSize() + // character buffer
+- (IsWriteFormats() ? (4 * GetFormatsCount()) : 0); // richtext formattting
++ GetHeaderSize() + // header
++ GetBufferSize() + // character buffer
++ (IsWriteFormats() ? (4 * GetFormatsCount()) : 0) + // richtext formattting
++ (IsWritePhoneticSettings() ? GetPhoneticSettingsCount() : 0); // phonetic settings
+ }
+
+ sal_uInt16 XclExpString::GetChar( sal_uInt16 nCharIdx ) const
+@@ -342,6 +364,10 @@ void XclExpString::WriteHeader( XclExpStream& rStrm ) const
+ // format run count
+ if( IsWriteFormats() )
+ rStrm << GetFormatsCount();
++ // format phonetic settings
++ if( IsWritePhoneticSettings() )
++ rStrm << GetPhoneticSettingsCount();
++
+ rStrm.SetSliceSize( 0 );
+ }
+
+@@ -378,12 +404,54 @@ void XclExpString::WriteFormats( XclExpStream& rStrm, bool bWriteSize ) const
+ }
+ }
+
++void XclExpString::WritePhoneticSettings( XclExpStream& rStrm ) const
++{
++ if( HasPhonetic() )
++ {
++ sal_uInt16 nLen = maPhonetic.GetString().Len();
++ sal_uInt16 nPortions = maPhonetic.GetPortions().size();
++ rStrm << static_cast< sal_uInt16 > ( 1 );
++ rStrm << static_cast< sal_uInt16 > ( 10 + 2 * nLen + 6 * nPortions );
++ rStrm << static_cast< sal_uInt16 > ( maPhonetic.GetFontIndex() );
++ rStrm << static_cast< sal_uInt16 > ( maPhonetic.GetAdditionalSettings() );
++ rStrm << static_cast< sal_uInt16 > ( nPortions );
++ rStrm << static_cast< sal_uInt16 > ( nLen );
++ rStrm << static_cast< sal_uInt16 > ( maPhonetic.GetRepeatedTotalLength() );
++
++ if ( nLen > 0 )
++ {
++ ScfUInt16Vec buffer ( nLen );
++ ScfUInt16Vec::iterator aBeg = buffer.begin();
++ ScfUInt16Vec::iterator aEnd = aBeg + nLen;
++ const sal_Unicode* pcSrcChar = maPhonetic.GetString().GetBuffer();
++ for( ScfUInt16Vec::iterator aIt = aBeg; aIt != aEnd; ++aIt, ++pcSrcChar )
++ {
++ *aIt = static_cast< sal_uInt16 >( *pcSrcChar );
++ }
++ rStrm.WriteUnicodeBuffer( buffer, EXC_STRF_16BIT);
++ }
++ else
++ {
++ rStrm << static_cast< sal_uInt16 > ( 0 );
++ }
++
++ PhoneticPortionVec portions = maPhonetic.GetPortions();
++ for ( sal_uInt16 idx = 0; idx < nPortions; ++idx)
++ {
++ PhoneticPortion portion = portions[idx];
++ rStrm << portion.mncpa << portion.mncpm << portion.mnccm;
++ }
++ }
++}
++
+ void XclExpString::Write( XclExpStream& rStrm ) const
+ {
+ WriteHeader( rStrm );
+ WriteBuffer( rStrm );
+ if( IsWriteFormats() ) // only in BIFF8 included in string
+ WriteFormats( rStrm );
++ if( IsWritePhoneticSettings() )
++ WritePhoneticSettings( rStrm );
+ }
+
+ void XclExpString::WriteHeaderToMem( sal_uInt8* pnMem ) const
+@@ -449,6 +517,11 @@ bool XclExpString::IsWriteFormats() const
+ return mbIsBiff8 && !mbSkipFormats && IsRich();
+ }
+
++bool XclExpString::IsWritePhoneticSettings() const
++{
++ return mbIsBiff8 && !mbSkipFormats && HasPhonetic();
++}
++
+ void XclExpString::SetStrLen( sal_Int32 nNewLen )
+ {
+ sal_uInt16 nAllowedLen = (mb8BitLen && (mnMaxLen > 255)) ? 255 : mnMaxLen;
+diff --git sc/source/filter/excel/xihelper.cxx sc/source/filter/excel/xihelper.cxx
+index 1a38697..0e44ba6 100644
+--- sc/source/filter/excel/xihelper.cxx
++++ sc/source/filter/excel/xihelper.cxx
+@@ -271,10 +271,20 @@ ScBaseCell* XclImpStringHelper::CreateCell(
+ ScDocument& rDoc = rRoot.GetDoc();
+
+ if( pTextObj.get() )
+- // ScEditCell creates own copy of text object
+- pCell = new ScEditCell( pTextObj.get(), &rDoc, rRoot.GetEditEngine().GetEditTextObjectPool() );
++ {
++ if ( rString.HasPhonetic() )
++ pCell = new ScAsianEditCell( pTextObj.get(), &rDoc, rRoot.GetEditEngine().GetEditTextObjectPool(), rString.GetPhonetic() );
++ else
++ // ScEditCell creates own copy of text object
++ pCell = new ScEditCell( pTextObj.get(), &rDoc, rRoot.GetEditEngine().GetEditTextObjectPool() );
++ }
+ else
+- pCell = ScBaseCell::CreateTextCell( rString.GetText(), &rDoc );
++ {
++ if ( rString.HasPhonetic() )
++ pCell = new ScAsianStringCell( rString.GetText(), rString.GetPhonetic() );
++ else
++ pCell = ScBaseCell::CreateTextCell( rString.GetText(), &rDoc );
++ }
+ }
+
+ return pCell;
+diff --git sc/source/filter/excel/xistring.cxx sc/source/filter/excel/xistring.cxx
+index 3d77ae0..48f8e87 100644
+--- sc/source/filter/excel/xistring.cxx
++++ sc/source/filter/excel/xistring.cxx
+@@ -94,7 +94,8 @@ void XclImpString::Read( XclImpStream& rStrm, XclStrFlags nFlags )
+ ReadFormats( rStrm, nRunCount );
+
+ // --- extended (FarEast) information ---
+- rStrm.Ignore( nExtInf );
++ if( nExtInf > 0 )
++ ReadPhoneticSettings( rStrm, nExtInf );
+ }
+ break;
+
+@@ -146,6 +147,31 @@ void XclImpString::ReadFormats( XclImpStream& rStrm, XclFormatRunVec& rFormats,
+ }
+ }
+
++void XclImpString::ReadPhoneticSettings( XclImpStream& rStrm, sal_uInt32 nExtInf )
++{
++ PhoneticPortionVec xPortions;
++
++ rStrm.Ignore( 2 ); // Unknown indentifier 0001
++
++ sal_uInt16 nSize, nFontIdx, nAdditional, nPortions, nLength, nRepeatedLength;
++ rStrm >> nSize >> nFontIdx >> nAdditional >> nPortions >> nLength >> nRepeatedLength;
++
++ if ( nLength == 0 )
++ rStrm.Ignore( 2 );
++ else
++ maPhoneticString = rStrm.ReadRawUniString( nLength, true );
++
++ for ( sal_uInt16 nIdx = 0; nIdx < nPortions; ++nIdx )
++ {
++ sal_uInt16 ncpa, ncpm, nccm;
++ rStrm >> ncpa >> ncpm >> nccm;
++ xPortions.push_back ( PhoneticPortion( ncpa, ncpm, nccm ) );
++ }
++
++ maPhonetic = ScPhonetic ( nFontIdx, nAdditional, nRepeatedLength,
++ maPhoneticString, xPortions );
++}
++
+ // String iterator ============================================================
+
+ XclImpStringIterator::XclImpStringIterator( const XclImpString& rString ) :
+diff --git sc/source/filter/excel/xlformula.cxx sc/source/filter/excel/xlformula.cxx
+index 8912407..3e0bc20 100644
+--- sc/source/filter/excel/xlformula.cxx
++++ sc/source/filter/excel/xlformula.cxx
+@@ -324,12 +324,12 @@ static const XclFunctionInfo saFuncTable_5[] =
+
+ const sal_Char* const EXC_FUNCNAME_BAHTTEXT = EXC_FUNCNAME_PREFIX "BAHTTEXT";
+
+-/** Functions new in BIFF8. Unsupported functions: PHONETIC. */
++/** Functions new in BIFF8. */
+ static const XclFunctionInfo saFuncTable_8[] =
+ {
+ { ocGetPivotData, 358, 2, 30, V, { V, R, V }, 0, 0 },
+ { ocHyperLink, 359, 1, 2, V, { V }, 0, 0 },
+- { ocNoName, 360, 1, 1, V, { R }, EXC_FUNCFLAG_IMPORTONLY, 0 }, // PHONETIC
++ { ocPhonetic, 360, 1, 1, V, { R }, 0, 0 }, // PHONETIC
+ { ocAverageA, 361, 1, 30, V, { R }, 0, 0 },
+ { ocMaxA, 362, 1, 30, V, { R }, 0, 0 },
+ { ocMinA, 363, 1, 30, V, { R }, 0, 0 },
+diff --git sc/source/filter/inc/xestring.hxx sc/source/filter/inc/xestring.hxx
+index d4ce93d..ac80cf6 100644
+--- sc/source/filter/inc/xestring.hxx
++++ sc/source/filter/inc/xestring.hxx
+@@ -32,11 +32,13 @@
+ #define SC_XESTRING_HXX
+
+ #include "xlstring.hxx"
++#include "phonetic.hxx"
+
+ // ============================================================================
+
+ class ScEditCell;
+ class ScPatternAttr;
++class ScPhonetic;
+ class EditTextObject;
+ class XclExpStream;
+
+@@ -161,6 +163,12 @@ public:
+ /** Removes and returns the font index for the first char from the formatting runs, otherwise EXC_FONT_NOTFOUND. */
+ sal_uInt16 RemoveLeadingFont();
+
++ // phonetic settings --------------------------------------------------------
++
++ /** Sets new phonetic settings for the current text.
++ @param rPhonetic a reference of ScPhonetic.*/
++ void SetPhoneticSettings( const ScPhonetic& rPhonetic );
++
+ // get data ---------------------------------------------------------------
+
+ /** Returns the character count of the string. */
+@@ -181,6 +189,11 @@ public:
+ /** Returns the vector with all formatting runs. */
+ inline const XclFormatRunVec& GetFormats() const { return maFormats; }
+
++ /** Returns the current count of phonetic settings */
++ sal_uInt32 GetPhoneticSettingsCount() const;
++ /** Returns true, if the string contains phonetic information. */
++ inline bool HasPhonetic() const;
++
+ /** Returns the current string flags field to export. */
+ sal_uInt8 GetFlagField() const;
+ /** Returns the byte count the header will take on export. */
+@@ -207,6 +220,8 @@ public:
+ void WriteBuffer( XclExpStream& rStrm ) const;
+ /** Writes the raw formatting run buffer. */
+ void WriteFormats( XclExpStream& rStrm, bool bWriteSize = false ) const;
++ /** Writes the raw phonetic settings. */
++ void WritePhoneticSettings( XclExpStream& rStrm ) const;
+ /** Writes the complete Unicode string. */
+ void Write( XclExpStream& rStrm ) const;
+
+@@ -223,6 +238,8 @@ private:
+ bool IsWriteFlags() const;
+ /** Returns true, if the formatting run vector should be written. */
+ bool IsWriteFormats() const;
++ /** Returns true, if phonetic settings of the text should be written. */
++ bool IsWritePhoneticSettings() const;
+
+ /** Sets the string length but regards the limit given in mnMaxLen. */
+ void SetStrLen( sal_Int32 nNewLen );
+@@ -277,6 +294,7 @@ private:
+ ScfUInt16Vec maUniBuffer; /// The Unicode character buffer.
+ ScfUInt8Vec maCharBuffer; /// The byte character buffer.
+ XclFormatRunVec maFormats; /// All formatting runs.
++ ScPhonetic maPhonetic;
+ sal_uInt16 mnLen; /// Character count to export.
+ sal_uInt16 mnMaxLen; /// Maximum allowed number of characters.
+ bool mbIsBiff8; /// true = BIFF8 Unicode string, false = BIFF2-7 bytestring.
+diff --git sc/source/filter/inc/xistring.hxx sc/source/filter/inc/xistring.hxx
+index 1be9886..046121f 100644
+--- sc/source/filter/inc/xistring.hxx
++++ sc/source/filter/inc/xistring.hxx
+@@ -32,6 +32,7 @@
+ #define SC_XISTRING_HXX
+
+ #include "xlstring.hxx"
++#include "phonetic.hxx"
+
+ // Byte/Unicode strings =======================================================
+
+@@ -79,9 +80,19 @@ public:
+ /** Reads and appends nRunCount formatting runs from stream. */
+ static void ReadFormats( XclImpStream& rStrm, XclFormatRunVec& rFormats, sal_uInt16 nRunCount );
+
++ /** Returns true, if the string has phonetic information. */
++ inline bool HasPhonetic() const { return !maPhonetic.IsEmpty(); }
++ /** Returns the text for phonetic information. */
++ inline const ScPhonetic& GetPhonetic() const { return maPhonetic; }
++
++ /** Reads phonetic settings from stream. */
++ void ReadPhoneticSettings( XclImpStream& rStrm, sal_uInt32 nExtInf );
++
+ private:
+ String maString; /// The text data of the string.
+ XclFormatRunVec maFormats; /// All formatting runs.
++ String maPhoneticString;
++ ScPhonetic maPhonetic;
+ };
+
+ // String iterator ============================================================
+diff --git sc/source/filter/inc/xlstring.hxx sc/source/filter/inc/xlstring.hxx
+index 626b11b..0b30049 100644
+--- sc/source/filter/inc/xlstring.hxx
++++ sc/source/filter/inc/xlstring.hxx
+@@ -93,7 +93,68 @@ inline bool operator<( const XclFormatRun& rLeft, const XclFormatRun& rRight )
+ /** A vector with all formatting runs for a rich-string. */
+ typedef ::std::vector< XclFormatRun > XclFormatRunVec;
+
+-// ============================================================================
++// Phonetic settings for Asian text ===========================================
++
++struct XclPhoneticPortion
++{
++ sal_uInt16 mncpa;
++ sal_uInt16 mncpm;
++ sal_uInt16 mnccm;
++ explicit inline XclPhoneticPortion() : mncpa( 0 ), mncpm( 0 ), mnccm( 0 ) {}
++ explicit inline XclPhoneticPortion( sal_uInt16 ncpa, sal_uInt16 ncpm, sal_uInt16 nccm ) :
++ mncpa( ncpa ), mncpm( ncpm ), mnccm ( nccm ) {}
++};
++
++inline bool operator==( const XclPhoneticPortion& rLeft, const XclPhoneticPortion& rRight )
++{
++ return
++ ( rLeft.mncpa == rRight.mncpa ) &&
++ ( rLeft.mncpm == rRight.mncpm ) &&
++ ( rLeft.mnccm == rRight.mnccm );
++}
++
++typedef ::std::vector< XclPhoneticPortion > XclPhoneticPortionVec;
++
++class XclPhoneticSettings
++{
++public:
++ explicit inline XclPhoneticSettings() : mnFontIdx( 0 ), mnAdditionalSettings( 0 ), mnRepeatedTotalLength ( 0 ) {}
++ explicit inline XclPhoneticSettings( sal_uInt16 nFontIdx, sal_uInt16 nAdditionalSettings,
++ sal_uInt16 nRepeatedTotalLength, const String& rPhoneticString,
++ const XclPhoneticPortionVec& rPhoneticPortions) :
++ mnFontIdx( nFontIdx ), mnAdditionalSettings( nAdditionalSettings ),
++ mnRepeatedTotalLength ( nRepeatedTotalLength ),
++ maPhoneticString ( rPhoneticString ), maPhoneticPortions ( rPhoneticPortions ) {}
++
++ /** Returns the text for phonetic information. */
++ inline const String& GetString() const { return maPhoneticString; }
++ /** Returns the portion for phonetic information. */
++ inline const XclPhoneticPortionVec& GetPortions() const { return maPhoneticPortions; }
++ /** Returns font index of phonetic information. */
++ inline sal_uInt16 GetFontIndex() const { return mnFontIdx; }
++ /** Returns additional settings of phonetic information. */
++ inline sal_uInt16 GetAdditionalSettings() const { return mnAdditionalSettings; }
++ /** Returns repeated length of phonetic information. */
++ inline sal_uInt16 GetRepeatedTotalLength() const { return mnRepeatedTotalLength; }
++ /** Returns the size of phonetic information. */
++ inline sal_uInt32 GetSize() const { return 14 + ( maPhoneticString.Len() ? maPhoneticString.Len() * 2 : 2 ) + maPhoneticPortions.size() * 6; }
++
++private:
++ sal_uInt16 mnFontIdx; /// Index to FONT record
++ sal_uInt16 mnAdditionalSettings; /// Additional settings for the Asian phonetic text
++ sal_uInt16 mnRepeatedTotalLength;
++ String maPhoneticString;
++ XclPhoneticPortionVec maPhoneticPortions;
++};
++inline bool operator==( const XclPhoneticSettings& rLeft, const XclPhoneticSettings& rRight )
++{
++ return
++ ( rLeft.GetString() == rRight.GetString() ) &&
++ ( rLeft.GetPortions() == rRight.GetPortions() ) &&
++ ( rLeft.GetFontIndex() == rRight.GetFontIndex() ) &&
++ ( rLeft.GetAdditionalSettings() == rRight.GetAdditionalSettings() ) &&
++ ( rLeft.GetRepeatedTotalLength() == rRight.GetRepeatedTotalLength() );
++}
+
+ #endif
+
+diff --git sc/source/filter/xml/XMLExportIterator.cxx sc/source/filter/xml/XMLExportIterator.cxx
+index 8a7e52b..29a2e2c 100644
+--- sc/source/filter/xml/XMLExportIterator.cxx
++++ sc/source/filter/xml/XMLExportIterator.cxx
+@@ -584,7 +584,8 @@ ScMyCell::ScMyCell() :
+ bHasXText( sal_False ),
+ bIsMatrixBase( sal_False ),
+ bIsMatrixCovered( sal_False ),
+- bHasAnnotation( sal_False )
++ bHasAnnotation( sal_False ),
++ bHasPhonetic( sal_False )
+ {
+ }
+
+diff --git sc/source/filter/xml/XMLExportIterator.hxx sc/source/filter/xml/XMLExportIterator.hxx
+index 0b0d51c..9d1834c 100644
+--- sc/source/filter/xml/XMLExportIterator.hxx
++++ sc/source/filter/xml/XMLExportIterator.hxx
+@@ -301,6 +301,7 @@ struct ScMyCell
+
+ rtl::OUString sStringValue;
+ rtl::OUString sAnnotationText;
++ rtl::OUString sPhoneticText;
+
+ ScMyAreaLink aAreaLink;
+ ScMyShapeList aShapeList;
+@@ -334,6 +335,7 @@ struct ScMyCell
+ sal_Bool bIsMatrixBase;
+ sal_Bool bIsMatrixCovered;
+ sal_Bool bHasAnnotation;
++ sal_Bool bHasPhonetic;
+
+ ScMyCell();
+ ~ScMyCell();
+diff --git sc/source/filter/xml/XMLTextPContext.cxx sc/source/filter/xml/XMLTextPContext.cxx
+index c4464b3..40f5e0b 100644
+--- sc/source/filter/xml/XMLTextPContext.cxx
++++ sc/source/filter/xml/XMLTextPContext.cxx
+@@ -37,6 +37,7 @@
+ #include "XMLTextPContext.hxx"
+ #include "xmlimprt.hxx"
+ #include "xmlcelli.hxx"
++#include "xmlrubyi.hxx"
+ #include <xmloff/xmlnmspe.hxx>
+ #include <xmloff/xmltoken.hxx>
+ #include <xmloff/nmspmap.hxx>
+@@ -137,52 +138,61 @@ SvXMLImportContext *ScXMLTextPContext::CreateChildContext( USHORT nTempPrefix,
+ ::com::sun::star::xml::sax::XAttributeList>& xTempAttrList )
+ {
+ SvXMLImportContext *pContext(NULL);
+- if (!pTextPContext &&
+- (nTempPrefix == XML_NAMESPACE_TEXT) &&
+- IsXMLToken(rLName, XML_S))
+- pContext = new ScXMLTextTContext( GetScImport(), nTempPrefix, rLName, xTempAttrList, this);
+- else
++
++ if ( !pTextPContext )
+ {
+- if (!pTextPContext)
++ const SvXMLTokenMap& rTokenMap = GetScImport().GetTableRowCellElemTextTokenMap();
++ switch( rTokenMap.Get( nTempPrefix, rLName ) )
+ {
+- rtl::OUString sSetString;
+- if ( pContentBuffer )
+- sSetString = pContentBuffer->makeStringAndClear();
+- else
+- sSetString = sSimpleContent;
+-
+- sal_Unicode cNonSpace(0);
+-
+- sal_Int32 nLength = sSetString.getLength();
+- if ( nLength > 0 )
++ case XML_TOK_TABLE_ROW_CELL_TEXT_S:
++ pContext = new ScXMLTextTContext( GetScImport(), nTempPrefix, rLName, xTempAttrList, this);
++ break;
++ case XML_TOK_TABLE_ROW_CELL_TEXT_RUBY:
++ pContext = new ScXMLRubyContext( GetScImport(), nTempPrefix, rLName, xTempAttrList, this );
++ break;
++ default:
+ {
+- sal_Unicode cLast = sSetString.getStr()[ nLength - 1 ];
+- if ( cLast != (sal_Unicode)' ' )
++ rtl::OUString sSetString;
++ if ( pContentBuffer )
++ sSetString = pContentBuffer->makeStringAndClear();
++ else
++ sSetString = sSimpleContent;
++
++ sal_Unicode cNonSpace(0);
++
++ sal_Int32 nLength = sSetString.getLength();
++ if ( nLength > 0 )
+ {
+- // #i53253# To keep XMLParaContext's whitespace handling in sync,
+- // if there's a non-space character at the end of the existing string,
+- // it has to be processed by XMLParaContext.
++ sal_Unicode cLast = sSetString.getStr()[ nLength - 1 ];
++ if ( cLast != (sal_Unicode)' ' )
++ {
++ // #i53253# To keep XMLParaContext's whitespace handling in sync,
++ // if there's a non-space character at the end of the existing string,
++ // it has to be processed by XMLParaContext.
+
+- cNonSpace = cLast;
+- sSetString = sSetString.copy( 0, nLength - 1 ); // remove from the string for SetCursorOnTextImport
++ cNonSpace = cLast;
++ sSetString = sSetString.copy( 0, nLength - 1 ); // remove from the string for SetCursorOnTextImport
++ }
+ }
+- }
+
+- pCellContext->SetCursorOnTextImport( sSetString );
++ pCellContext->SetCursorOnTextImport( sSetString );
+
+- pTextPContext = GetScImport().GetTextImport()->CreateTextChildContext(
+- GetScImport(), nPrefix, sLName, xAttrList);
++ pTextPContext = GetScImport().GetTextImport()->CreateTextChildContext(
++ GetScImport(), nPrefix, sLName, xAttrList);
+
+- if ( cNonSpace != 0 )
+- {
+- // pass non-space character through XMLParaContext, so a following space isn't ignored
+- pTextPContext->Characters( rtl::OUString( cNonSpace ) );
++ if ( cNonSpace != 0 )
++ {
++ // pass non-space character through XMLParaContext, so a following space isn't ignored
++ pTextPContext->Characters( rtl::OUString( cNonSpace ) );
++ }
+ }
++ break;
+ }
+- if (pTextPContext)
+- pContext = pTextPContext->CreateChildContext(nTempPrefix, rLName, xTempAttrList);
+ }
+
++ if ( pTextPContext )
++ pContext = pTextPContext->CreateChildContext(nTempPrefix, rLName, xTempAttrList);
++
+ if( !pContext )
+ pContext = new SvXMLImportContext( GetScImport(), nTempPrefix, rLName );
+
+@@ -223,5 +233,38 @@ void ScXMLTextPContext::EndElement()
+ pTextPContext->EndElement();
+ GetScImport().SetRemoveLastChar(sal_True);
+ }
++ if ( sOURubyText )
++ pCellContext->SetPhoneticText( sOURubyText.makeStringAndClear() );
++}
++
++void ScXMLTextPContext::GetContent( rtl::OUString& rContent )
++{
++ if (!pTextPContext)
++ {
++ if ( pContentBuffer )
++ {
++ rtl::OUStringBuffer tmpBuffer( *pContentBuffer );
++ rContent = tmpBuffer.makeStringAndClear();
++ }
++ else
++ {
++ rContent = sSimpleContent;
++ }
++ }
++}
++
++void ScXMLTextPContext::AddRubyText( const ::rtl::OUString &rBaseText, const ::rtl::OUString& rRubyText )
++{
++ rtl::OUString aContent;
++ GetContent( aContent );
++
++ sal_uInt16 startIdx = aContent.getLength();
++ sal_uInt16 endIdx = rBaseText.getLength();
++
++ PhoneticPortion portion( sOURubyText.getLength(), startIdx, endIdx );
++ sOURubyText.append( rRubyText );
++ aPhoneticPortions.push_back( portion );
++
++ Characters ( rBaseText );
+ }
+
+diff --git sc/source/filter/xml/XMLTextPContext.hxx sc/source/filter/xml/XMLTextPContext.hxx
+index eb759e7..3235159 100644
+--- sc/source/filter/xml/XMLTextPContext.hxx
++++ sc/source/filter/xml/XMLTextPContext.hxx
+@@ -34,6 +34,8 @@
+ #include <xmloff/xmlictxt.hxx>
+ #include <rtl/ustrbuf.hxx>
+
++#include "phonetic.hxx"
++
+ class ScXMLImport;
+ class ScXMLTableRowCellContext;
+
+@@ -47,9 +49,12 @@ class ScXMLTextPContext : public SvXMLImportContext
+ rtl::OUStringBuffer* pContentBuffer; // used if there's more than one string
+ USHORT nPrefix;
+ sal_Bool bIsOwn;
++ rtl::OUStringBuffer sOURubyText;
++ PhoneticPortionVec aPhoneticPortions;
+
+ const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
+ ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
++ void GetContent( rtl::OUString& rContent );
+
+ public:
+ ScXMLTextPContext( ScXMLImport& rImport, USHORT nPrfx,
+@@ -70,6 +75,14 @@ public:
+ virtual void EndElement();
+
+ void AddSpaces(sal_Int32 nSpaceCount);
++
++ /**
++ * Add phonetic and base text into cell.
++ *
++ * @param rBaseText the base string.
++ * @param rRubyText the phonetic text.
++ */
++ void AddRubyText( const ::rtl::OUString& rBaseText, const ::rtl::OUString& rRubyText );
+ };
+
+ #endif
+diff --git sc/source/filter/xml/makefile.mk sc/source/filter/xml/makefile.mk
+index d44da6b..b0f31f8 100644
+--- sc/source/filter/xml/makefile.mk
++++ sc/source/filter/xml/makefile.mk
+@@ -73,6 +73,7 @@ CXXFILES = \
+ xmlannoi.cxx \
+ xmlsceni.cxx \
+ xmlcvali.cxx \
++ xmlrubyi.cxx \
+ XMLTableMasterPageExport.cxx \
+ xmllabri.cxx \
+ XMLTableHeaderFooterContext.cxx \
+@@ -123,6 +124,7 @@ SLOFILES = \
+ $(SLO)$/xmlannoi.obj \
+ $(SLO)$/xmlsceni.obj \
+ $(SLO)$/xmlcvali.obj \
++ $(SLO)$/xmlrubyi.obj \
+ $(SLO)$/XMLTableMasterPageExport.obj \
+ $(SLO)$/xmllabri.obj \
+ $(SLO)$/XMLTableHeaderFooterContext.obj \
+diff --git sc/source/filter/xml/xmlcelli.cxx sc/source/filter/xml/xmlcelli.cxx
+index a990e54..7ae6ee0 100644
+--- sc/source/filter/xml/xmlcelli.cxx
++++ sc/source/filter/xml/xmlcelli.cxx
+@@ -38,6 +38,7 @@
+ #include "xmltabi.hxx"
+ #include "xmlstyli.hxx"
+ #include "xmlannoi.hxx"
++#include "xmlrubyi.hxx"
+ #include "global.hxx"
+ #include "document.hxx"
+ #include "cellsuno.hxx"
+@@ -117,6 +118,7 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport,
+ pOUTextValue(NULL),
+ pOUTextContent(NULL),
+ pOUFormula(NULL),
++ pOUPhoneticText(NULL),
+ pContentValidationName(NULL),
+ pMyAnnotation(NULL),
+ pDetectiveObjVec(NULL),
+@@ -297,6 +299,9 @@ ScXMLTableRowCellContext::~ScXMLTableRowCellContext()
+ delete pDetectiveObjVec;
+ if (pCellRangeSource)
+ delete pCellRangeSource;
++
++ // no need to check for NULL-ness when 'delete'-ing a pointer.
++ delete pOUPhoneticText;
+ }
+
+ void ScXMLTableRowCellContext::LockSolarMutex()
+@@ -459,6 +464,12 @@ SvXMLImportContext *ScXMLTableRowCellContext::CreateChildContext( USHORT nPrefix
+ rXMLImport, nPrefix, rLName, xAttrList, pCellRangeSource );
+ }
+ break;
++ case XML_TOK_TABLE_ROW_CELL_RUBY:
++ {
++ bIsEmpty = sal_False;
++ pContext = new ScXMLRubyContext( rXMLImport, nPrefix, rLName, xAttrList, this );
++ }
++ break;
+ }
+
+ if (!pContext && !bTextP)
+@@ -755,6 +766,81 @@ bool lcl_IsEmptyOrNote( ScDocument* pDoc, const table::CellAddress& rCurrentPos
+ return ( !pCell || pCell->GetCellType() == CELLTYPE_NOTE );
+ }
+
++static sal_Bool lcl_IsHalfWidthKatakana ( const ::rtl::OUString& rString )
++{
++ const sal_Unicode *pString = rString.getStr();
++ sal_Int32 nLen = rString.getLength();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( pString[i] < 0xFF00 || pString[i] > 0xFFEF )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_Bool lcl_IsFullWidthKatakana ( const ::rtl::OUString& rString )
++{
++ const sal_Unicode *pString = rString.getStr();
++ sal_Int32 nLen = rString.getLength();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( pString[i] < 0x30A0 || pString[i] > 0x30FF )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_Bool lcl_IsFullWidthHiragana ( const ::rtl::OUString& rString )
++{
++ const sal_Unicode *pString = rString.getStr();
++ sal_Int32 nLen = rString.getLength();
++
++ for ( sal_Int32 i = 0; i < nLen; ++i )
++ {
++ if ( pString[i] < 0x3040 || pString[i] > 0x309F )
++ return sal_False;
++ }
++
++ return sal_True;
++}
++
++static sal_uInt16 lcl_GetKanaType ( const ::rtl::OUString* pText )
++{
++ sal_uInt16 aKanaType = 0;
++
++ if ( lcl_IsHalfWidthKatakana ( *pText ) )
++ aKanaType = 0x00;
++ else if ( lcl_IsFullWidthKatakana ( *pText ) )
++ aKanaType = 0x01;
++ else if ( lcl_IsFullWidthHiragana ( *pText ) )
++ aKanaType = 0x02;
++
++ return aKanaType;
++}
++
++static ScBaseCell* lcl_CreateTextCell ( const String& rString, ScDocument* pDoc, const ::rtl::OUString* pPhoneticText )
++{
++ ScBaseCell *pCell = 0;
++
++ if ( pPhoneticText && pPhoneticText->getLength() )
++ {
++ PhoneticPortionVec xPortions;
++ sal_uInt16 aKanaType = lcl_GetKanaType ( pPhoneticText );
++ ScPhonetic aPhonetic ( 0, 0x30 | aKanaType , 0, *pPhoneticText, xPortions );
++ pCell = new ScAsianStringCell( rString, aPhonetic );
++ }
++ else
++ {
++ pCell = ScBaseCell::CreateTextCell( rString, pDoc );
++ }
++
++ return pCell;
++}
++
+ void ScXMLTableRowCellContext::EndElement()
+ {
+ if (!bHasSubTable)
+@@ -925,11 +1011,11 @@ void ScXMLTableRowCellContext::EndElement()
+ ScBaseCell* pNewCell = NULL;
+ ScDocument* pDoc = rXMLImport.GetDocument();
+ if (pOUTextValue && pOUTextValue->getLength())
+- pNewCell = ScBaseCell::CreateTextCell( *pOUTextValue, pDoc );
++ pNewCell = lcl_CreateTextCell( *pOUTextValue, pDoc, pOUPhoneticText );
+ else if (pOUTextContent && pOUTextContent->getLength())
+- pNewCell = ScBaseCell::CreateTextCell( *pOUTextContent, pDoc );
++ pNewCell = lcl_CreateTextCell( *pOUTextContent, pDoc, pOUPhoneticText );
+ else if ( i > 0 && pOUText && pOUText->getLength() )
+- pNewCell = ScBaseCell::CreateTextCell( *pOUText, pDoc );
++ pNewCell = lcl_CreateTextCell( *pOUText, pDoc, pOUPhoneticText );
+ if ( pNewCell )
+ {
+ ScAddress aScAddress;
+@@ -1016,6 +1102,18 @@ void ScXMLTableRowCellContext::EndElement()
+ }
+ else
+ {
++ if ( pOUPhoneticText && pOUPhoneticText->getLength() )
++ {
++ ScAddress aScAddress;
++ ScDocument* pDoc = rXMLImport.GetDocument();
++ ScUnoConversion::FillScAddress( aScAddress, aCurrentPos );
++ ScBaseCell *pBaseCell = pDoc->GetCell( aScAddress );
++ PhoneticPortionVec xPortions;
++ sal_uInt16 aKanaType = lcl_GetKanaType ( pOUPhoneticText );
++ ScPhonetic aPhonetic ( 0, 0x30 | aKanaType , 0, *pOUPhoneticText, xPortions );
++ ScBaseCell *pNewCell = new ScAsianEditCell( (const ScEditCell&) *pBaseCell, pDoc, aPhonetic );
++ pDoc->PutCell( aScAddress, pNewCell );
++ }
+ // #i56027# If the child context put formatted text into the cell,
+ // bIsEmpty is TRUE and ProgressBarIncrement has to be called
+ // with bEditCell = TRUE.
+@@ -1122,3 +1220,10 @@ void ScXMLTableRowCellContext::EndElement()
+ nMergedRows = 1;
+ nCellsRepeated = 1;
+ }
++
++void ScXMLTableRowCellContext::SetPhoneticText(const rtl::OUString& rOUPhoneticText)
++{
++ delete pOUPhoneticText;
++ pOUPhoneticText = new ::rtl::OUString(rOUPhoneticText);
++}
++
+diff --git sc/source/filter/xml/xmlcelli.hxx sc/source/filter/xml/xmlcelli.hxx
+index 589077d..192637d 100644
+--- sc/source/filter/xml/xmlcelli.hxx
++++ sc/source/filter/xml/xmlcelli.hxx
+@@ -71,6 +71,7 @@ class ScXMLTableRowCellContext : public SvXMLImportContext
+ rtl::OUString* pOUTextContent;
+ rtl::OUString* pOUFormula;
+ rtl::OUString* pContentValidationName;
++ rtl::OUString* pOUPhoneticText;
+ ScMyImportAnnotation* pMyAnnotation;
+ ScMyImpDetectiveObjVec* pDetectiveObjVec;
+ ScMyImpCellRangeSource* pCellRangeSource;
+@@ -142,6 +143,13 @@ public:
+ virtual void EndElement();
+
+ void AddAnnotation(ScMyImportAnnotation* pValue) { pMyAnnotation = pValue; }
++
++ /**
++ * Set phonetic text.
++ *
++ * @param rOUPhoneticText the phonetic text
++ */
++ void SetPhoneticText(const rtl::OUString& rOUPhoneticText);
+ };
+
+ #endif
+diff --git sc/source/filter/xml/xmlexprt.cxx sc/source/filter/xml/xmlexprt.cxx
+index 2baaac4..e286f06 100644
+--- sc/source/filter/xml/xmlexprt.cxx
++++ sc/source/filter/xml/xmlexprt.cxx
+@@ -2270,11 +2270,27 @@ sal_Bool ScXMLExport::GetCellText (ScMyCell& rMyCell, const ScAddress& aPos) con
+ // {
+ rMyCell.sStringValue = ScCellObj::GetOutputString_Impl(pDoc, aPos);
+ rMyCell.bHasStringValue = sal_True;
++ rMyCell.sPhoneticText = ScCellObj::GetOutputPhoneticString_Impl(pDoc, aPos);
++ rMyCell.bHasPhonetic = sal_True;
+ return sal_True;
+ // }
+ }
+ }
+
++void ScXMLExport::WriteRubyText (ScMyCell& rMyCell)
++{
++ if ( !rMyCell.sPhoneticText.getLength() )
++ return;
++ StartElement( XML_NAMESPACE_TEXT, XML_RUBY, sal_False);
++ StartElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE, sal_False );
++ Characters( rMyCell.sStringValue );
++ EndElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE, sal_False );
++ StartElement( XML_NAMESPACE_TEXT, XML_RUBY_TEXT, sal_False );
++ Characters( rMyCell.sPhoneticText );
++ EndElement( XML_NAMESPACE_TEXT, XML_RUBY_TEXT, sal_False );
++ EndElement( XML_NAMESPACE_TEXT, XML_RUBY, sal_False);
++}
++
+ void ScXMLExport::WriteCell (ScMyCell& aCell)
+ {
+ ScAddress aCellPos;
+@@ -2418,13 +2434,20 @@ void ScXMLExport::WriteCell (ScMyCell& aCell)
+ uno::Reference<text::XText> xText(xCurrentTableCellRange->getCellByPosition(aCell.aCellAddress.Column, aCell.aCellAddress.Row), uno::UNO_QUERY);
+ if ( xText.is())
+ GetTextParagraphExport()->exportText(xText, sal_False, sal_False);
++ if (GetCellText( aCell, aCellPos ) && aCell.sPhoneticText.getLength())
++ WriteRubyText( aCell );
+ }
+ else
+ {
+ SvXMLElementExport aElemP(*this, sElemP, sal_True, sal_False);
+ sal_Bool bPrevCharWasSpace(sal_True);
+ if (GetCellText(aCell, aCellPos))
+- GetTextParagraphExport()->exportText(aCell.sStringValue, bPrevCharWasSpace);
++ {
++ if ( aCell.sPhoneticText.getLength() )
++ WriteRubyText( aCell );
++ else
++ GetTextParagraphExport()->exportText( aCell.sStringValue, bPrevCharWasSpace );
++ }
+ }
+ }
+ WriteShapes(aCell);
+diff --git sc/source/filter/xml/xmlexprt.hxx sc/source/filter/xml/xmlexprt.hxx
+index 03e3469..119c79a 100644
+--- sc/source/filter/xml/xmlexprt.hxx
++++ sc/source/filter/xml/xmlexprt.hxx
+@@ -183,6 +183,12 @@ class ScXMLExport : public SvXMLExport
+ void ExportShape(const com::sun::star::uno::Reference < com::sun::star::drawing::XShape >& xShape, com::sun::star::awt::Point* pPoint);
+ void WriteShapes(const ScMyCell& rMyCell);
+ void WriteTableShapes();
++
++ /**
++ * Write phonetic text
++ * @param aCell the cell reference which has phonetic text.
++ */
++ void WriteRubyText (ScMyCell& aCell);
+ void SetRepeatAttribute (const sal_Int32 nEqualCellCount);
+
+ sal_Bool IsCellTypeEqual (const ScMyCell& aCell1, const ScMyCell& aCell2) const;
+diff --git sc/source/filter/xml/xmlimprt.cxx sc/source/filter/xml/xmlimprt.cxx
+index 6d4bc86..095d7f0 100644
+--- sc/source/filter/xml/xmlimprt.cxx
++++ sc/source/filter/xml/xmlimprt.cxx
+@@ -415,7 +415,28 @@ static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTokenMap[] =
+ { XML_NAMESPACE_OFFICE, XML_ANNOTATION, XML_TOK_TABLE_ROW_CELL_ANNOTATION },
+ { XML_NAMESPACE_TABLE, XML_DETECTIVE, XML_TOK_TABLE_ROW_CELL_DETECTIVE },
+ { XML_NAMESPACE_TABLE, XML_CELL_RANGE_SOURCE, XML_TOK_TABLE_ROW_CELL_CELL_RANGE_SOURCE },
+- XML_TOKEN_MAP_END
++ { XML_NAMESPACE_TEXT, XML_RUBY, XML_TOK_TABLE_ROW_CELL_RUBY },
++ XML_TOKEN_MAP_END
++};
++
++static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTextTokenMap[] =
++{
++ { XML_NAMESPACE_TEXT, XML_S, XML_TOK_TABLE_ROW_CELL_TEXT_S },
++ { XML_NAMESPACE_TEXT, XML_RUBY, XML_TOK_TABLE_ROW_CELL_TEXT_RUBY },
++ XML_TOKEN_MAP_END
++};
++
++static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTextRubyAttrTokenMap[] =
++{
++ { XML_NAMESPACE_TEXT, XML_STYLE_NAME, XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_ATTR_STYLE_NAME },
++ XML_TOKEN_MAP_END
++};
++
++static __FAR_DATA SvXMLTokenMapEntry aTableRowCellTextRubyTokenMap[] =
++{
++ { XML_NAMESPACE_TEXT, XML_RUBY_BASE, XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_BASE },
++ { XML_NAMESPACE_TEXT, XML_RUBY_TEXT, XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_TEXT },
++ XML_TOKEN_MAP_END
+ };
+
+ static __FAR_DATA SvXMLTokenMapEntry aTableRowCellAttrTokenMap[] =
+@@ -1097,6 +1118,27 @@ const SvXMLTokenMap& ScXMLImport::GetTableRowCellElemTokenMap()
+ return *pTableRowCellElemTokenMap;
+ }
+
++const SvXMLTokenMap& ScXMLImport::GetTableRowCellElemTextTokenMap()
++{
++ if( !pTableRowCellElemTextTokenMap )
++ pTableRowCellElemTextTokenMap = new SvXMLTokenMap( aTableRowCellTextTokenMap );
++ return *pTableRowCellElemTextTokenMap;
++}
++
++const SvXMLTokenMap& ScXMLImport::GetTableRowCellElemTextRubyTokenMap()
++{
++ if( !pTableRowCellElemTextRubyTokenMap )
++ pTableRowCellElemTextRubyTokenMap = new SvXMLTokenMap( aTableRowCellTextRubyTokenMap );
++ return *pTableRowCellElemTextRubyTokenMap;
++}
++
++const SvXMLTokenMap& ScXMLImport::GetTableRowCellElemTextRubyAttrTokenMap()
++{
++ if( !pTableRowCellElemTextRubyAttrTokenMap )
++ pTableRowCellElemTextRubyAttrTokenMap = new SvXMLTokenMap( aTableRowCellTextRubyAttrTokenMap );
++ return *pTableRowCellElemTextRubyAttrTokenMap;
++}
++
+ const SvXMLTokenMap& ScXMLImport::GetTableRowCellAttrTokenMap()
+ {
+ if( !pTableRowCellAttrTokenMap )
+@@ -1464,6 +1506,9 @@ ScXMLImport::ScXMLImport(
+ pTableRowElemTokenMap( 0 ),
+ pTableRowAttrTokenMap( 0 ),
+ pTableRowCellElemTokenMap( 0 ),
++ pTableRowCellElemTextTokenMap( 0 ),
++ pTableRowCellElemTextRubyTokenMap( 0 ),
++ pTableRowCellElemTextRubyAttrTokenMap( 0 ),
+ pTableRowCellAttrTokenMap( 0 ),
+ pTableAnnotationAttrTokenMap( 0 ),
+ pDetectiveElemTokenMap( 0 ),
+@@ -1590,6 +1635,9 @@ ScXMLImport::~ScXMLImport() throw()
+ delete pTableRowElemTokenMap;
+ delete pTableRowAttrTokenMap;
+ delete pTableRowCellElemTokenMap;
++ delete pTableRowCellElemTextTokenMap;
++ delete pTableRowCellElemTextRubyTokenMap;
++ delete pTableRowCellElemTextRubyAttrTokenMap;
+ delete pTableRowCellAttrTokenMap;
+ delete pTableAnnotationAttrTokenMap;
+ delete pDetectiveElemTokenMap;
+diff --git sc/source/filter/xml/xmlimprt.hxx sc/source/filter/xml/xmlimprt.hxx
+index be0bc22..f9bdcf1 100644
+--- sc/source/filter/xml/xmlimprt.hxx
++++ sc/source/filter/xml/xmlimprt.hxx
+@@ -248,7 +248,25 @@ enum ScXMLTableRowCellTokens
+ XML_TOK_TABLE_ROW_CELL_TABLE,
+ XML_TOK_TABLE_ROW_CELL_ANNOTATION,
+ XML_TOK_TABLE_ROW_CELL_DETECTIVE,
+- XML_TOK_TABLE_ROW_CELL_CELL_RANGE_SOURCE
++ XML_TOK_TABLE_ROW_CELL_CELL_RANGE_SOURCE,
++ XML_TOK_TABLE_ROW_CELL_RUBY
++};
++
++enum ScXMLTableRowCellTextTokens
++{
++ XML_TOK_TABLE_ROW_CELL_TEXT_S,
++ XML_TOK_TABLE_ROW_CELL_TEXT_RUBY
++};
++
++enum ScXMLTableRowCellTextRubyTokens
++{
++ XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_BASE,
++ XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_TEXT
++};
++
++enum ScXMLTableRowCellTextRubyAttrTokens
++{
++ XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_ATTR_STYLE_NAME
+ };
+
+ enum ScXMLTableRowCellAttrTokens
+@@ -690,6 +708,9 @@ class ScXMLImport: public SvXMLImport
+ SvXMLTokenMap *pTableRowElemTokenMap;
+ SvXMLTokenMap *pTableRowAttrTokenMap;
+ SvXMLTokenMap *pTableRowCellElemTokenMap;
++ SvXMLTokenMap *pTableRowCellElemTextTokenMap;
++ SvXMLTokenMap *pTableRowCellElemTextRubyTokenMap;
++ SvXMLTokenMap *pTableRowCellElemTextRubyAttrTokenMap;
+ SvXMLTokenMap *pTableRowCellAttrTokenMap;
+ SvXMLTokenMap *pTableAnnotationAttrTokenMap;
+ SvXMLTokenMap *pDetectiveElemTokenMap;
+@@ -851,6 +872,9 @@ public:
+ const SvXMLTokenMap& GetTableRowElemTokenMap();
+ const SvXMLTokenMap& GetTableRowAttrTokenMap();
+ const SvXMLTokenMap& GetTableRowCellElemTokenMap();
++ const SvXMLTokenMap& GetTableRowCellElemTextTokenMap();
++ const SvXMLTokenMap& GetTableRowCellElemTextRubyTokenMap();
++ const SvXMLTokenMap& GetTableRowCellElemTextRubyAttrTokenMap();
+ const SvXMLTokenMap& GetTableRowCellAttrTokenMap();
+ const SvXMLTokenMap& GetTableAnnotationAttrTokenMap();
+ const SvXMLTokenMap& GetDetectiveElemTokenMap();
+diff --git sc/source/filter/xml/xmlrubyi.cxx sc/source/filter/xml/xmlrubyi.cxx
+new file mode 100644
+index 0000000..98414d5
+--- /dev/null
++++ sc/source/filter/xml/xmlrubyi.cxx
+@@ -0,0 +1,207 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: global.hxx,v $
++ * $Revision: 1.53 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org. If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++// MARKER(update_precomp.py): autogen include statement, do not remove
++#include "precompiled_sc.hxx"
++
++
++
++// INCLUDE ---------------------------------------------------------------
++
++#ifndef _SC_XMLRUBYI_HXX
++#include "xmlrubyi.hxx"
++#endif
++#ifndef SC_XMLIMPRT_HXX
++#include "xmlimprt.hxx"
++#endif
++#ifndef SC_XMLCELLI_HXX
++#include "xmlcelli.hxx"
++#endif
++#ifndef _SC_XMLTEXTPCONTEXT_HXX
++#include "XMLTextPContext.hxx"
++#endif
++#ifndef _XMLSTYLI_HXX
++#include "xmlstyli.hxx"
++#endif
++
++#ifndef _XMLOFF_XMLNMSPE_HXX
++#include <xmloff/xmlnmspe.hxx>
++#endif
++#ifndef _XMLOFF_XMLTOKEN_HXX
++#include <xmloff/xmltoken.hxx>
++#endif
++#ifndef _XMLOFF_NMSPMAP_HXX
++#include <xmloff/nmspmap.hxx>
++#endif
++#ifndef _TOOLS_DEBUG_HXX
++#include <tools/debug.hxx>
++#endif
++#ifndef _COM_SUN_STAR_TEXT_XTEXT_HPP_
++#include <com/sun/star/text/XText.hpp>
++#endif
++
++using namespace com::sun::star;
++using namespace xmloff::token;
++
++ScXMLRubyContext::ScXMLRubyContext( ScXMLImport& rImport,
++ USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xTempAttrList,
++ ScXMLTextPContext* pTempTextContext) :
++ SvXMLImportContext( rImport, nPrfx, rLName ),
++ pCellContext( NULL ),
++ pTextContext( pTempTextContext )
++{
++ sal_Int16 nAttrCount(xTempAttrList.is() ? xTempAttrList->getLength() : 0);
++ const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableRowCellElemTextRubyAttrTokenMap();
++ for( sal_Int16 i=0; i < nAttrCount; ++i )
++ {
++ const rtl::OUString& sAttrName(xTempAttrList->getNameByIndex( i ));
++ rtl::OUString aLocalName;
++ USHORT nPrefix(GetScImport().GetNamespaceMap().GetKeyByAttrName(
++ sAttrName, &aLocalName ));
++ const rtl::OUString& sValue(xTempAttrList->getValueByIndex( i ));
++
++ switch( rAttrTokenMap.Get( nPrefix, aLocalName ) )
++ {
++ case XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_ATTR_STYLE_NAME:
++ sStyleName = sValue;
++ break;
++ }
++ }
++}
++
++ScXMLRubyContext::ScXMLRubyContext( ScXMLImport& rImport,
++ USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xTempAttrList,
++ ScXMLTableRowCellContext* pTempContext) :
++ SvXMLImportContext( rImport, nPrfx, rLName ),
++ pCellContext( pTempContext ),
++ pTextContext( NULL )
++{
++ sal_Int16 nAttrCount(xTempAttrList.is() ? xTempAttrList->getLength() : 0);
++ const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetTableRowCellElemTextRubyAttrTokenMap();
++ for( sal_Int16 i=0; i < nAttrCount; ++i )
++ {
++ const rtl::OUString& sAttrName(xTempAttrList->getNameByIndex( i ));
++ rtl::OUString aLocalName;
++ USHORT nPrefix(GetScImport().GetNamespaceMap().GetKeyByAttrName(
++ sAttrName, &aLocalName ));
++ const rtl::OUString& sValue(xTempAttrList->getValueByIndex( i ));
++
++ switch( rAttrTokenMap.Get( nPrefix, aLocalName ) )
++ {
++ case XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_ATTR_STYLE_NAME:
++ sStyleName = sValue;
++ break;
++ }
++ }
++}
++
++SvXMLImportContext *ScXMLRubyContext::CreateChildContext( USHORT nPrefix,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList )
++{
++ SvXMLImportContext *pContext(NULL);
++
++ const SvXMLTokenMap& rTokenMap = GetScImport().GetTableRowCellElemTextRubyTokenMap();
++ switch( rTokenMap.Get( nPrefix, rLName ) )
++ {
++ case XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_BASE:
++ pContext = new ScXMLRubyBaseContext( GetScImport(), nPrefix, rLName, xAttrList, this);
++ break;
++ case XML_TOK_TABLE_ROW_CELL_TEXT_RUBY_TEXT:
++ pContext = new ScXMLRubyTextContext( GetScImport(), nPrefix, rLName, xAttrList, this);
++ break;
++ }
++
++ if( !pContext )
++ pContext = new SvXMLImportContext( GetScImport(), nPrefix, rLName );
++
++ return pContext;
++}
++
++void ScXMLRubyContext::EndElement()
++{
++ if ( pTextContext )
++ pTextContext->AddRubyText( sBaseText.makeStringAndClear(), sRubyText.makeStringAndClear() );
++ else if ( pCellContext )
++ pCellContext->SetPhoneticText( sRubyText.makeStringAndClear() );
++}
++
++void ScXMLRubyContext::AddBaseText( const ::rtl::OUString& rText )
++{
++ sBaseText.append( rText );
++}
++
++void ScXMLRubyContext::AddRubyText( const ::rtl::OUString& rText )
++{
++ sRubyText.append( rText );
++}
++
++ScXMLRubyBaseContext::ScXMLRubyBaseContext( ScXMLImport& rImport,
++ USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xTempAttrList,
++ ScXMLRubyContext* pTempRubyContext) :
++ SvXMLImportContext( rImport, nPrfx, rLName ),
++ pRubyContext( pTempRubyContext )
++{
++ // here are no attributes
++}
++
++void ScXMLRubyBaseContext::Characters( const ::rtl::OUString& rChars )
++{
++ pRubyContext->AddBaseText( rChars );
++}
++
++ScXMLRubyTextContext::ScXMLRubyTextContext( ScXMLImport& rImport,
++ USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xTempAttrList,
++ ScXMLRubyContext* pTempRubyContext) :
++ SvXMLImportContext( rImport, nPrfx, rLName ),
++ pRubyContext( pTempRubyContext )
++{
++ // here are no attributes
++}
++
++void ScXMLRubyTextContext::Characters( const ::rtl::OUString& rChars )
++{
++ pRubyContext->AddRubyText( rChars );
++}
++
++
+diff --git sc/source/filter/xml/xmlrubyi.hxx sc/source/filter/xml/xmlrubyi.hxx
+new file mode 100644
+index 0000000..5af457e
+--- /dev/null
++++ sc/source/filter/xml/xmlrubyi.hxx
+@@ -0,0 +1,191 @@
++/*************************************************************************
++ *
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * Copyright 2008 by Sun Microsystems, Inc.
++ *
++ * OpenOffice.org - a multi-platform office productivity suite
++ *
++ * $RCSfile: global.hxx,v $
++ * $Revision: 1.53 $
++ *
++ * This file is part of OpenOffice.org.
++ *
++ * OpenOffice.org is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 3
++ * only, as published by the Free Software Foundation.
++ *
++ * OpenOffice.org is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU Lesser General Public License version 3 for more details
++ * (a copy is included in the LICENSE file that accompanied this code).
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * version 3 along with OpenOffice.org. If not, see
++ * <http://www.openoffice.org/license.html>
++ * for a copy of the LGPLv3 License.
++ *
++ ************************************************************************/
++
++#ifndef _SC_XMLRUBYI_HXX
++#define _SC_XMLRUBYI_HXX
++
++#ifndef _XMLOFF_XMLICTXT_HXX
++#include <xmloff/xmlictxt.hxx>
++#endif
++#ifndef _RTL_USTRBUF_HXX_
++#include <rtl/ustrbuf.hxx>
++#endif
++
++class ScXMLImport;
++class ScXMLTextPContext;
++class ScXMLTableRowCellContext;
++
++/**
++ * A class for representing Asian phonetic guide information while loading ODF file.
++ */
++class ScXMLRubyContext : public SvXMLImportContext
++{
++ rtl::OUString sStyleName;
++ rtl::OUStringBuffer sBaseText;
++ rtl::OUStringBuffer sRubyText;
++ ScXMLTextPContext* pTextContext;
++ ScXMLTableRowCellContext* pCellContext;
++
++ const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
++ ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
++
++public:
++
++ /**
++ * A constructor of ScXMLRubyContext.
++ * @param rImport a reference of ScXMLImport.
++ * @param nPrfx the number of the element prefix.
++ * @param rLName the string of the element.
++ * @param xAttrList attribute list of the element.
++ * @param pContext a pointer of ScXMLTextPContext.
++ */
++ ScXMLRubyContext( ScXMLImport& rImport, USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++ ScXMLTextPContext* pContext);
++ /**
++ * A constructor of ScXMLRubyContext.
++ * @param rImport a reference of ScXMLImport.
++ * @param nPrfx the number of the element prefix.
++ * @param rLName the string of the element.
++ * @param xAttrList attribute list of the element.
++ * @param pContext a pointer of ScXMLTableRowCellContext.
++ */
++ ScXMLRubyContext( ScXMLImport& rImport, USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++ ScXMLTableRowCellContext* pContext);
++
++ virtual ~ScXMLRubyContext() {};
++
++ /**
++ * Create a childs element context. By default, the import's
++ * CreateContext method is called to create a new default context.
++ * @return a new default context.
++ */
++ virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix,
++ const ::rtl::OUString& rLocalName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
++ /**
++ * EndElement is called before a context will be destructed, but
++ * after a elements context has been parsed. It may be used for actions
++ * that require virtual methods. The default is to do nothing.
++ */
++ virtual void EndElement();
++
++ /**
++ * Adds string into cell string as base string of phonetic infrmation
++ * @param rText the base string.
++ */
++ void AddBaseText(const ::rtl::OUString& rText);
++ /**
++ * Adds string into cell string as phonetic text
++ * @param rText the phonetic text.
++ */
++ void AddRubyText(const ::rtl::OUString& rText);
++};
++
++/**
++ * A class for representing base text of phonetic guide information while loading ODF file.
++ */
++class ScXMLRubyBaseContext : public SvXMLImportContext
++{
++ ScXMLRubyContext* pRubyContext;
++
++ const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
++ ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
++
++public:
++
++ /**
++ * A constructor of ScXMLRubyBaseContext.
++ * @param rImport a reference of ScXMLImport.
++ * @param nPrfx the number of the element prefix.
++ * @param rLName the string of the element.
++ * @param xAttrList attribute list of the element.
++ * @param pContext a pointer of ScXMLRubyContext.
++ */
++ ScXMLRubyBaseContext( ScXMLImport& rImport, USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++ ScXMLRubyContext* pContext);
++
++ virtual ~ScXMLRubyBaseContext() {};
++
++ /**
++ * This method is called for all characters that are contained in the
++ * current element. The default is to ignore them.
++ * @param rChars the character reference
++ */
++ virtual void Characters( const ::rtl::OUString& rChars );
++};
++
++
++/**
++ * A class for representing phonetic text of phonetic guide information while loading ODF file.
++ */
++class ScXMLRubyTextContext : public SvXMLImportContext
++{
++ ScXMLRubyContext* pRubyContext;
++
++ const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
++ ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
++
++public:
++
++ /**
++ * A constructor of ScXMLRubyTextContext.
++ * @param rImport a reference of ScXMLImport.
++ * @param nPrfx the number of the element prefix.
++ * @param rLName the string of the element.
++ * @param xAttrList attribute list of the element.
++ * @param pContext a pointer of ScXMLRubyContext.
++ */
++ ScXMLRubyTextContext( ScXMLImport& rImport, USHORT nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference<
++ ::com::sun::star::xml::sax::XAttributeList>& xAttrList,
++ ScXMLRubyContext* pContext);
++
++ virtual ~ScXMLRubyTextContext() {};
++
++ /**
++ * This method is called for all characters that are contained in the
++ * current element. The default is to ignore them.
++ * @param rChars the character reference
++ */
++ virtual void Characters( const ::rtl::OUString& rChars );
++};
++
++#endif
+diff --git sc/source/filter/xml/xmlstyle.cxx sc/source/filter/xml/xmlstyle.cxx
+index 863e82c..56e92b8 100644
+--- sc/source/filter/xml/xmlstyle.cxx
++++ sc/source/filter/xml/xmlstyle.cxx
+@@ -140,6 +140,7 @@ const XMLPropertyMapEntry aXMLScRowStylesImportProperties[] =
+ MAP( "IsCellBackgroundTransparent", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_PROP_TABLE_ROW|XML_TYPE_ISTRANSPARENT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ),
+ MAP( "IsManualPageBreak", XML_NAMESPACE_FO, XML_BREAK_BEFORE, XML_TYPE_PROP_TABLE_ROW|XML_SC_TYPE_BREAKBEFORE, CTF_SC_ROWBREAKBEFORE),
+ MAP( "OptimalHeight", XML_NAMESPACE_STYLE, XML_USE_OPTIMAL_ROW_HEIGHT, XML_TYPE_PROP_TABLE_ROW|XML_TYPE_BOOL, CTF_SC_ROWOPTIMALHEIGHT),
++ MAP( "RubyText", XML_NAMESPACE_TEXT, XML_RUBY_TEXT, XML_TYPE_PROP_RUBY, 0 ),
+ MAP_END()
+ };
+
+diff --git sc/source/filter/xml/xmlstyli.cxx sc/source/filter/xml/xmlstyli.cxx
+index 9624740..87584b1 100644
+--- sc/source/filter/xml/xmlstyli.cxx
++++ sc/source/filter/xml/xmlstyli.cxx
+@@ -64,8 +64,9 @@
+ #define XML_LINE_BLTR 1
+
+ using ::rtl::OUString;
++using ::com::sun::star::uno::UNO_QUERY;
++using ::com::sun::star::uno::Reference;
+ using namespace ::com::sun::star;
+-using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::xml::sax;
+ using namespace ::com::sun::star::style;
+ using namespace ::com::sun::star::frame;
+@@ -695,22 +696,30 @@ SvXMLStyleContext *XMLTableStylesContext::CreateStyleStyleChildContext(
+ sal_uInt16 nFamily, sal_uInt16 nPrefix, const OUString& rLocalName,
+ const uno::Reference< xml::sax::XAttributeList > & xAttrList )
+ {
+- SvXMLStyleContext *pStyle(SvXMLStylesContext::CreateStyleStyleChildContext( nFamily, nPrefix,
+- rLocalName,
+- xAttrList ));
+- if (!pStyle)
+- {
+- switch( nFamily )
+- {
+- case XML_STYLE_FAMILY_TABLE_CELL:
+- case XML_STYLE_FAMILY_TABLE_COLUMN:
+- case XML_STYLE_FAMILY_TABLE_ROW:
+- case XML_STYLE_FAMILY_TABLE_TABLE:
+- pStyle = new XMLTableStyleContext( GetScImport(), nPrefix, rLocalName,
+- xAttrList, *this, nFamily );
+- break;
+- }
+- }
++ SvXMLStyleContext *pStyle(NULL);
++ if ( nFamily == XML_STYLE_FAMILY_TEXT_RUBY )
++ {
++ pStyle = new XMLRubyStyleContext ( GetScImport(), nPrefix, rLocalName,
++ xAttrList, *this, nFamily );
++ }
++ else
++ {
++ pStyle = SvXMLStylesContext::CreateStyleStyleChildContext(
++ nFamily, nPrefix, rLocalName, xAttrList );
++ if (!pStyle)
++ {
++ switch( nFamily )
++ {
++ case XML_STYLE_FAMILY_TABLE_CELL:
++ case XML_STYLE_FAMILY_TABLE_COLUMN:
++ case XML_STYLE_FAMILY_TABLE_ROW:
++ case XML_STYLE_FAMILY_TABLE_TABLE:
++ pStyle = new XMLTableStyleContext( GetScImport(), nPrefix, rLocalName,
++ xAttrList, *this, nFamily );
++ break;
++ }
++ }
++ }
+
+ return pStyle;
+ }
+@@ -1081,3 +1090,102 @@ void ScMasterPageContext::Finish( sal_Bool bOverwrite )
+ if (!bContainsRightHeader)
+ ClearContent(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNO_PAGE_RIGHTHDRCON)));
+ }
++
++class ScXMLRubyStyleContext : public SvXMLImportContext
++{
++ rtl::OUString sPosition;
++ rtl::OUString sAlign;
++public:
++
++ ScXMLRubyStyleContext(
++ SvXMLImport& rImport, sal_uInt16 nPrfx,
++ const rtl::OUString& rLName,
++ const Reference< XAttributeList > & xAttrList );
++ virtual ~ScXMLRubyStyleContext();
++
++ const rtl::OUString& GetPosition() const { return sPosition; }
++ const rtl::OUString& GetAlign() const { return sAlign; }
++};
++
++ScXMLRubyStyleContext::ScXMLRubyStyleContext(SvXMLImport& rImport, sal_uInt16 nPrfx,
++ const OUString& rLName, const Reference< XAttributeList > & xAttrList )
++ : SvXMLImportContext( rImport, nPrfx, rLName ),
++ sPosition(),
++ sAlign()
++{
++ sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0);
++ for( sal_Int16 i=0; i < nAttrCount; ++i )
++ {
++ const OUString& rAttrName(xAttrList->getNameByIndex( i ));
++ OUString aLocalName;
++ sal_uInt16 nPrefix(GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName ));
++ const OUString& rValue(xAttrList->getValueByIndex( i ));
++
++ if( XML_NAMESPACE_STYLE == nPrefix )
++ {
++ if( IsXMLToken(aLocalName, XML_RUBY_ALIGN ) )
++ sPosition = rValue;
++ else if( IsXMLToken(aLocalName, XML_RUBY_POSITION ) )
++ sAlign = rValue;
++ }
++ }
++}
++
++ScXMLRubyStyleContext::~ScXMLRubyStyleContext()
++{
++}
++
++TYPEINIT1( XMLRubyStyleContext, XMLPropStyleContext );
++
++XMLRubyStyleContext::XMLRubyStyleContext( ScXMLImport& rImport,
++ sal_uInt16 nPrfx, const OUString& rLName,
++ const Reference< XAttributeList > & xAttrList,
++ SvXMLStylesContext& rStyles, sal_uInt16 nFamily, sal_Bool bDefaultStyle ) :
++ XMLPropStyleContext( rImport, nPrfx, rLName, xAttrList, rStyles, nFamily, bDefaultStyle ),
++ pStyles(&rStyles)
++{
++}
++
++XMLRubyStyleContext::~XMLRubyStyleContext()
++{
++}
++
++SvXMLImportContext *XMLRubyStyleContext::CreateChildContext(
++ sal_uInt16 nPrefix,
++ const OUString& rLocalName,
++ const Reference< XAttributeList > & xAttrList )
++{
++ SvXMLImportContext *pContext(NULL);
++
++ if( (XML_NAMESPACE_STYLE == nPrefix) &&
++ IsXMLToken(rLocalName, XML_RUBY_PROPERTIES ) )
++ {
++ pContext = new ScXMLRubyStyleContext(GetImport(), nPrefix, rLocalName, xAttrList);
++ sPosition = ((ScXMLRubyStyleContext*)pContext)->GetPosition();
++ sAlign = ((ScXMLRubyStyleContext*)pContext)->GetAlign();
++ }
++ if (!pContext)
++ pContext = XMLPropStyleContext::CreateChildContext( nPrefix, rLocalName,
++ xAttrList );
++ return pContext;
++}
++
++void XMLRubyStyleContext::FillPropertySet( const Reference< XPropertySet > & rPropSet )
++{
++ XMLPropStyleContext::FillPropertySet(rPropSet);
++}
++
++void XMLRubyStyleContext::SetDefaults()
++{
++ if ((GetFamily() == XML_STYLE_FAMILY_TEXT_RUBY) && GetImport().GetModel().is())
++ {
++ uno::Reference <lang::XMultiServiceFactory> xMultiServiceFactory(GetImport().GetModel(), uno::UNO_QUERY);
++ if (xMultiServiceFactory.is())
++ {
++ uno::Reference <beans::XPropertySet> xProperties(xMultiServiceFactory->createInstance(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.sheet.Defaults"))), uno::UNO_QUERY);
++ if (xProperties.is())
++ FillPropertySet(xProperties);
++ }
++ }
++}
++
+diff --git sc/source/filter/xml/xmlstyli.hxx sc/source/filter/xml/xmlstyli.hxx
+index 237e8e3..ead1581 100644
+--- sc/source/filter/xml/xmlstyli.hxx
++++ sc/source/filter/xml/xmlstyli.hxx
+@@ -258,6 +258,59 @@ public:
+ virtual void EndElement();
+ };
+
++/**
++ * A class for representing ruby style while loading ODF file.
++ */
++class XMLRubyStyleContext : public XMLPropStyleContext
++{
++ SvXMLStylesContext* pStyles;
++ rtl::OUString sPosition;
++ rtl::OUString sAlign;
++
++ const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); }
++ ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); }
++
++public:
++
++ TYPEINFO();
++
++ /**
++ * A constructor of XMLRubyStyleContext.
++ * @param rImport a reference of ScXMLImport.
++ * @param nPrfx the number of the element prefix.
++ * @param rLName the string of the element.
++ * @param xAttrList attribute list of the element.
++ * @param rStyles a reference of SvXMLStylesContext.
++ * @param bDefaultStyle a flag of use of default style.
++ */
++ XMLRubyStyleContext( ScXMLImport& rImport, sal_uInt16 nPrfx,
++ const ::rtl::OUString& rLName,
++ const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList,
++ SvXMLStylesContext& rStyles, sal_uInt16 nFamily, sal_Bool bDefaultStyle = sal_False );
++ virtual ~XMLRubyStyleContext();
++
++ /**
++ * Create a childs element context. By default, the import's
++ * CreateContext method is called to create a new default context.
++ * @param nPrefix
++ * @param rLocalName
++ * @param xAttrList
++ * @return a new default context.
++ */
++ virtual SvXMLImportContext *CreateChildContext(
++ sal_uInt16 nPrefix,
++ const ::rtl::OUString& rLocalName,
++ const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList > & xAttrList );
++
++ virtual void FillPropertySet(const ::com::sun::star::uno::Reference<
++ ::com::sun::star::beans::XPropertySet > & rPropSet );
++
++ virtual void SetDefaults();
++
++private:
++ using XMLPropStyleContext::SetStyle;
++};
++
+ namespace com { namespace sun { namespace star {
+ namespace style { class XStyle; }
+ } } }
+diff --git sc/source/ui/src/scfuncs.src sc/source/ui/src/scfuncs.src
+index 27e6868..fd230d3 100644
+--- sc/source/ui/src/scfuncs.src
++++ sc/source/ui/src/scfuncs.src
+@@ -7884,6 +7884,33 @@ Resource RID_SC_FUNCTION_DESCRIPTIONS2
+ Text [ en-US ] = "The text to convert.";
+ };
+ };
++ // -=*# Resource for function PHONETIC #*=-
++ Resource SC_OPCODE_PHONETIC
++ {
++ String 1 // Description
++ {
++ Text [ en-US ] = "Returns a phonetic guide text." ;
++ Text [ ja ] = "ããããæååãèãããã" ;
++ };
++ ExtraData =
++ {
++ 0;
++ ID_FUNCTION_GRP_TEXT;
++ U2S( HID_FUNC_PHONETIC );
++ 1; 0;
++ 0;
++ };
++ String 2 // Name of Parameter 1
++ {
++ Text [ en-US ] = "range" ;
++ Text [ ja ] = "çå" ;
++ };
++ String 3 // Description of Parameter 1
++ {
++ Text [ en-US ] = "The cell range from which phonetic guide texts are retrieved." ;
++ Text [ ja ] = "ããããæååãåãåãããçåã" ;
++ };
++ };
+ // -=*# Resource for function CODE #*=-
+ Resource SC_OPCODE_CODE
+ {
+diff --git sc/source/ui/unoobj/cellsuno.cxx sc/source/ui/unoobj/cellsuno.cxx
+index 7c0e769..d3e5576 100644
+--- sc/source/ui/unoobj/cellsuno.cxx
++++ sc/source/ui/unoobj/cellsuno.cxx
+@@ -6235,6 +6235,32 @@ String ScCellObj::GetOutputString_Impl(ScDocument* pDoc, const ScAddress& aCellP
+ return aVal;
+ }
+
++String ScCellObj::GetOutputPhoneticString_Impl(ScDocument* pDoc, const ScAddress& aCellPos)
++{
++ String aVal;
++ if ( pDoc )
++ {
++ ScBaseCell* pCell = pDoc->GetCell( aCellPos );
++ if ( pCell && pCell->GetCellType() == CELLTYPE_STRING &&
++ static_cast<const ScStringCell*>(pCell)->HasPhonetic() )
++ {
++ ScPhonetic aPhonetic;
++ static_cast<const ScAsianStringCell*>(pCell)->GetPhonetic(aPhonetic);
++ if ( !aPhonetic.IsEmpty() )
++ aVal = aPhonetic.GetString();
++ }
++ else if ( pCell && pCell->GetCellType() == CELLTYPE_EDIT &&
++ static_cast<const ScEditCell*>(pCell)->HasPhonetic() )
++ {
++ ScPhonetic aPhonetic;
++ static_cast<const ScAsianEditCell*>(pCell)->GetPhonetic(aPhonetic);
++ if ( !aPhonetic.IsEmpty() )
++ aVal = aPhonetic.GetString();
++ }
++ }
++ return aVal;
++}
++
+ String ScCellObj::GetOutputString_Impl() const
+ {
+ ScDocShell* pDocSh = GetDocShell();
+diff --git sc/util/hidother.src sc/util/hidother.src
+index 9d7ec65..3a9cbf7 100644
+--- sc/util/hidother.src
++++ sc/util/hidother.src
+@@ -389,6 +389,7 @@ hidspecial HID_FUNC_UNICODE { HelpID = HID_FUNC_UNICODE; };
+ hidspecial HID_FUNC_UNICHAR { HelpID = HID_FUNC_UNICHAR; };
+ hidspecial HID_FUNC_EUROCONVERT { HelpID = HID_FUNC_EUROCONVERT; };
+ hidspecial HID_FUNC_NUMBERVALUE { HelpID = HID_FUNC_NUMBERVALUE; };
++hidspecial HID_FUNC_PHONETIC { HelpID = HID_FUNC_PHONETIC; };
+
+ // ... and from Analysis Addin
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]