diff options
Diffstat (limited to '')
-rw-r--r-- | editeng/source/editeng/eehtml.cxx | 820 |
1 files changed, 820 insertions, 0 deletions
diff --git a/editeng/source/editeng/eehtml.cxx b/editeng/source/editeng/eehtml.cxx new file mode 100644 index 000000000..0820c48df --- /dev/null +++ b/editeng/source/editeng/eehtml.cxx @@ -0,0 +1,820 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "eehtml.hxx" +#include <editeng/adjustitem.hxx> +#include <editeng/flditem.hxx> +#include <tools/urlobj.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> +#include <tools/tenccvt.hxx> + +#include <editeng/editeng.hxx> +#include <utility> + +#define STYLE_PRE 101 + +EditHTMLParser::EditHTMLParser( SvStream& rIn, OUString _aBaseURL, SvKeyValueIterator* pHTTPHeaderAttrs ) + : HTMLParser( rIn, true ), + aBaseURL(std::move( _aBaseURL )), + mpEditEngine(nullptr), + bInPara(false), + bWasInPara(false), + bFieldsInserted(false), + bInTitle(false), + nInTable(0), + nInCell(0), + nDefListLevel(0) +{ + DBG_ASSERT( !IsSwitchToUCS2(), "EditHTMLParser::::EditHTMLParser: Switch to UCS2?" ); + + // Although the real default encoding is ISO8859-1, we use MS-1252 + // as default encoding. + SetSrcEncoding( GetExtendedCompatibilityTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); + + // If the file starts with a BOM, switch to UCS2. + SetSwitchToUCS2( true ); + + if ( pHTTPHeaderAttrs ) + SetEncodingByHTTPHeader( pHTTPHeaderAttrs ); +} + +EditHTMLParser::~EditHTMLParser() +{ +} + +SvParserState EditHTMLParser::CallParser(EditEngine* pEE, const EditPaM& rPaM) +{ + DBG_ASSERT(pEE, "CallParser: ImpEditEngine ?!"); + mpEditEngine = pEE; + SvParserState _eState = SvParserState::NotStarted; + if ( mpEditEngine ) + { + // Build in wrap mimic in RTF import? + aCurSel = EditSelection( rPaM, rPaM ); + + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::Start, this, mpEditEngine->CreateESelection(aCurSel)); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + + ImpSetStyleSheet( 0 ); + _eState = HTMLParser::CallParser(); + + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::End, this, mpEditEngine->CreateESelection(aCurSel)); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + + if ( bFieldsInserted ) + mpEditEngine->UpdateFieldsOnly(); + } + return _eState; +} + +void EditHTMLParser::NextToken( HtmlTokenId nToken ) +{ + switch( nToken ) + { + case HtmlTokenId::META: + { + const HTMLOptions& aOptions = GetOptions(); + size_t nArrLen = aOptions.size(); + bool bEquiv = false; + for ( size_t i = 0; i < nArrLen; i++ ) + { + const HTMLOption& aOption = aOptions[i]; + switch( aOption.GetToken() ) + { + case HtmlOptionId::HTTPEQUIV: + { + bEquiv = true; + } + break; + case HtmlOptionId::CONTENT: + { + if ( bEquiv ) + { + rtl_TextEncoding eEnc = GetEncodingByMIME( aOption.GetString() ); + if ( eEnc != RTL_TEXTENCODING_DONTKNOW ) + SetSrcEncoding( eEnc ); + } + } + break; + default: break; + } + } + + } + break; + case HtmlTokenId::PLAINTEXT_ON: + case HtmlTokenId::PLAINTEXT2_ON: + bInPara = true; + break; + case HtmlTokenId::PLAINTEXT_OFF: + case HtmlTokenId::PLAINTEXT2_OFF: + bInPara = false; + break; + + case HtmlTokenId::LINEBREAK: + case HtmlTokenId::NEWPARA: + { + if ( ( bInPara || nInTable ) && + ( ( nToken == HtmlTokenId::LINEBREAK ) || HasTextInCurrentPara() ) ) + { + ImpInsertParaBreak(); + } + } + break; + case HtmlTokenId::HORZRULE: + { + if ( HasTextInCurrentPara() ) + ImpInsertParaBreak(); + ImpInsertParaBreak(); + } + break; + case HtmlTokenId::NONBREAKSPACE: + { + if ( bInPara ) + { + ImpInsertText( " " ); + } + } + break; + case HtmlTokenId::RAWDATA: + if (IsReadStyle() && !aToken.isEmpty()) + { + // Each token represents a single line. + maStyleSource.append(aToken); + maStyleSource.append('\n'); + } + break; + case HtmlTokenId::TEXTTOKEN: + { + // #i110937# for <title> content, call aImportHdl (no SkipGroup), but don't insert the text into the EditEngine + if (!bInTitle) + { + if ( !bInPara ) + StartPara( false ); + + OUString aText = aToken.toString(); + if ( aText.startsWith(" ") && ThrowAwayBlank() && !IsReadPRE() ) + aText = aText.copy( 1 ); + + if ( pCurAnchor ) + { + pCurAnchor->aText += aText; + } + else + { + // Only written until HTML with 319? + if ( IsReadPRE() ) + { + sal_Int32 nTabPos = aText.indexOf( '\t'); + while ( nTabPos != -1 ) + { + aText = aText.replaceAt( nTabPos, 1, u" " ); + nTabPos = aText.indexOf( '\t', nTabPos+8 ); + } + } + ImpInsertText( aText ); + } + } + } + break; + + case HtmlTokenId::CENTER_ON: + case HtmlTokenId::CENTER_OFF: + { + sal_Int32 nNode = mpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + aItems.ClearItem( EE_PARA_JUST ); + if ( nToken == HtmlTokenId::CENTER_ON ) + aItems.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) ); + mpEditEngine->SetParaAttribsOnly(nNode, aItems); + } + break; + + case HtmlTokenId::ANCHOR_ON: AnchorStart(); + break; + case HtmlTokenId::ANCHOR_OFF: AnchorEnd(); + break; + + case HtmlTokenId::PARABREAK_ON: + if( bInPara && HasTextInCurrentPara() ) + EndPara(); + StartPara( true ); + break; + + case HtmlTokenId::PARABREAK_OFF: + if( bInPara ) + EndPara(); + break; + + case HtmlTokenId::HEAD1_ON: + case HtmlTokenId::HEAD2_ON: + case HtmlTokenId::HEAD3_ON: + case HtmlTokenId::HEAD4_ON: + case HtmlTokenId::HEAD5_ON: + case HtmlTokenId::HEAD6_ON: + { + HeadingStart( nToken ); + } + break; + + case HtmlTokenId::HEAD1_OFF: + case HtmlTokenId::HEAD2_OFF: + case HtmlTokenId::HEAD3_OFF: + case HtmlTokenId::HEAD4_OFF: + case HtmlTokenId::HEAD5_OFF: + case HtmlTokenId::HEAD6_OFF: + { + HeadingEnd(); + } + break; + + case HtmlTokenId::PREFORMTXT_ON: + case HtmlTokenId::XMP_ON: + case HtmlTokenId::LISTING_ON: + { + StartPara( true ); + ImpSetStyleSheet( STYLE_PRE ); + } + break; + + case HtmlTokenId::DEFLIST_ON: + { + nDefListLevel++; + } + break; + + case HtmlTokenId::DEFLIST_OFF: + { + if( nDefListLevel ) + nDefListLevel--; + } + break; + + case HtmlTokenId::TABLE_ON: nInTable++; + break; + case HtmlTokenId::TABLE_OFF: DBG_ASSERT( nInTable, "Not in Table, but TABLE_OFF?" ); + nInTable--; + break; + + case HtmlTokenId::TABLEHEADER_ON: + case HtmlTokenId::TABLEDATA_ON: + nInCell++; + [[fallthrough]]; + case HtmlTokenId::BLOCKQUOTE_ON: + case HtmlTokenId::BLOCKQUOTE_OFF: + case HtmlTokenId::BLOCKQUOTE30_ON: + case HtmlTokenId::BLOCKQUOTE30_OFF: + case HtmlTokenId::LISTHEADER_ON: + case HtmlTokenId::LI_ON: + case HtmlTokenId::DD_ON: + case HtmlTokenId::DT_ON: + case HtmlTokenId::ORDERLIST_ON: + case HtmlTokenId::UNORDERLIST_ON: + { + bool bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + StartPara( false ); + } + break; + + case HtmlTokenId::TABLEHEADER_OFF: + case HtmlTokenId::TABLEDATA_OFF: + { + if ( nInCell ) + nInCell--; + [[fallthrough]]; + } + case HtmlTokenId::LISTHEADER_OFF: + case HtmlTokenId::LI_OFF: + case HtmlTokenId::DD_OFF: + case HtmlTokenId::DT_OFF: + case HtmlTokenId::ORDERLIST_OFF: + case HtmlTokenId::UNORDERLIST_OFF: EndPara(); + break; + + case HtmlTokenId::TABLEROW_ON: + case HtmlTokenId::TABLEROW_OFF: // A RETURN only after a CELL, for Calc + + case HtmlTokenId::COL_ON: + case HtmlTokenId::COLGROUP_ON: + case HtmlTokenId::COLGROUP_OFF: break; + + case HtmlTokenId::FONT_ON: + break; + case HtmlTokenId::FONT_OFF: + break; + + case HtmlTokenId::TITLE_ON: + bInTitle = true; + break; + case HtmlTokenId::TITLE_OFF: + bInTitle = false; + break; + + // globals + case HtmlTokenId::HTML_ON: + case HtmlTokenId::HTML_OFF: + case HtmlTokenId::STYLE_ON: + case HtmlTokenId::STYLE_OFF: + case HtmlTokenId::BODY_ON: + case HtmlTokenId::BODY_OFF: + case HtmlTokenId::HEAD_ON: + case HtmlTokenId::HEAD_OFF: + case HtmlTokenId::FORM_ON: + case HtmlTokenId::FORM_OFF: + case HtmlTokenId::THEAD_ON: + case HtmlTokenId::THEAD_OFF: + case HtmlTokenId::TBODY_ON: + case HtmlTokenId::TBODY_OFF: + // inline elements, structural markup + // HTML 3.0 + case HtmlTokenId::BANNER_ON: + case HtmlTokenId::BANNER_OFF: + case HtmlTokenId::DIVISION_ON: + case HtmlTokenId::DIVISION_OFF: +// case HtmlTokenId::LISTHEADER_ON: //! special handling +// case HtmlTokenId::LISTHEADER_OFF: + case HtmlTokenId::NOTE_ON: + case HtmlTokenId::NOTE_OFF: + // inline elements, logical markup + // HTML 2.0 + case HtmlTokenId::ADDRESS_ON: + case HtmlTokenId::ADDRESS_OFF: +// case HtmlTokenId::BLOCKQUOTE_ON: //! special handling +// case HtmlTokenId::BLOCKQUOTE_OFF: + case HtmlTokenId::CITATION_ON: + case HtmlTokenId::CITATION_OFF: + case HtmlTokenId::CODE_ON: + case HtmlTokenId::CODE_OFF: + case HtmlTokenId::DEFINSTANCE_ON: + case HtmlTokenId::DEFINSTANCE_OFF: + case HtmlTokenId::EMPHASIS_ON: + case HtmlTokenId::EMPHASIS_OFF: + case HtmlTokenId::KEYBOARD_ON: + case HtmlTokenId::KEYBOARD_OFF: + case HtmlTokenId::SAMPLE_ON: + case HtmlTokenId::SAMPLE_OFF: + case HtmlTokenId::STRIKE_ON: + case HtmlTokenId::STRIKE_OFF: + case HtmlTokenId::STRONG_ON: + case HtmlTokenId::STRONG_OFF: + case HtmlTokenId::VARIABLE_ON: + case HtmlTokenId::VARIABLE_OFF: + // HTML 3.0 + case HtmlTokenId::ABBREVIATION_ON: + case HtmlTokenId::ABBREVIATION_OFF: + case HtmlTokenId::ACRONYM_ON: + case HtmlTokenId::ACRONYM_OFF: + case HtmlTokenId::AUTHOR_ON: + case HtmlTokenId::AUTHOR_OFF: +// case HtmlTokenId::BLOCKQUOTE30_ON: //! special handling +// case HtmlTokenId::BLOCKQUOTE30_OFF: + case HtmlTokenId::DELETEDTEXT_ON: + case HtmlTokenId::DELETEDTEXT_OFF: + case HtmlTokenId::INSERTEDTEXT_ON: + case HtmlTokenId::INSERTEDTEXT_OFF: + case HtmlTokenId::LANGUAGE_ON: + case HtmlTokenId::LANGUAGE_OFF: + case HtmlTokenId::PERSON_ON: + case HtmlTokenId::PERSON_OFF: + case HtmlTokenId::SHORTQUOTE_ON: + case HtmlTokenId::SHORTQUOTE_OFF: + case HtmlTokenId::SUBSCRIPT_ON: + case HtmlTokenId::SUBSCRIPT_OFF: + case HtmlTokenId::SUPERSCRIPT_ON: + case HtmlTokenId::SUPERSCRIPT_OFF: + // inline elements, visual markup + // HTML 2.0 + case HtmlTokenId::BOLD_ON: + case HtmlTokenId::BOLD_OFF: + case HtmlTokenId::ITALIC_ON: + case HtmlTokenId::ITALIC_OFF: + case HtmlTokenId::TELETYPE_ON: + case HtmlTokenId::TELETYPE_OFF: + case HtmlTokenId::UNDERLINE_ON: + case HtmlTokenId::UNDERLINE_OFF: + // HTML 3.0 + case HtmlTokenId::BIGPRINT_ON: + case HtmlTokenId::BIGPRINT_OFF: + case HtmlTokenId::STRIKETHROUGH_ON: + case HtmlTokenId::STRIKETHROUGH_OFF: + case HtmlTokenId::SMALLPRINT_ON: + case HtmlTokenId::SMALLPRINT_OFF: + // figures + case HtmlTokenId::FIGURE_ON: + case HtmlTokenId::FIGURE_OFF: + case HtmlTokenId::CAPTION_ON: + case HtmlTokenId::CAPTION_OFF: + case HtmlTokenId::CREDIT_ON: + case HtmlTokenId::CREDIT_OFF: + // misc + case HtmlTokenId::DIRLIST_ON: + case HtmlTokenId::DIRLIST_OFF: + case HtmlTokenId::FOOTNOTE_ON: //! they land so in the text + case HtmlTokenId::FOOTNOTE_OFF: + case HtmlTokenId::MENULIST_ON: + case HtmlTokenId::MENULIST_OFF: +// case HtmlTokenId::PLAINTEXT_ON: //! special handling +// case HtmlTokenId::PLAINTEXT_OFF: +// case HtmlTokenId::PREFORMTXT_ON: //! special handling +// case HtmlTokenId::PREFORMTXT_OFF: + case HtmlTokenId::SPAN_ON: + case HtmlTokenId::SPAN_OFF: + // obsolete +// case HtmlTokenId::XMP_ON: //! special handling +// case HtmlTokenId::XMP_OFF: +// case HtmlTokenId::LISTING_ON: //! special handling +// case HtmlTokenId::LISTING_OFF: + // Netscape + case HtmlTokenId::BLINK_ON: + case HtmlTokenId::BLINK_OFF: + case HtmlTokenId::NOBR_ON: + case HtmlTokenId::NOBR_OFF: + case HtmlTokenId::NOEMBED_ON: + case HtmlTokenId::NOEMBED_OFF: + case HtmlTokenId::NOFRAMES_ON: + case HtmlTokenId::NOFRAMES_OFF: + // Internet Explorer + case HtmlTokenId::MARQUEE_ON: + case HtmlTokenId::MARQUEE_OFF: +// case HtmlTokenId::PLAINTEXT2_ON: //! special handling +// case HtmlTokenId::PLAINTEXT2_OFF: + break; + + default: + { + if ( nToken >= HtmlTokenId::ONOFF_START ) + { + if ( ( nToken == HtmlTokenId::UNKNOWNCONTROL_ON ) || ( nToken == HtmlTokenId::UNKNOWNCONTROL_OFF ) ) + { + ; + } + else if ( !isOffToken(nToken) ) + { + DBG_ASSERT( !isOffToken( nToken ), "No Start-Token ?!" ); + SkipGroup( static_cast<HtmlTokenId>(static_cast<int>(nToken) + 1) ); + } + } + } + } // SWITCH + + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::NextToken, this, mpEditEngine->CreateESelection(aCurSel)); + aImportInfo.nToken = nToken; + if ( nToken == HtmlTokenId::TEXTTOKEN ) + aImportInfo.aText = aToken; + else if (nToken == HtmlTokenId::STYLE_OFF) + aImportInfo.aText = maStyleSource.makeStringAndClear(); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + +} + +void EditHTMLParser::ImpInsertParaBreak() +{ + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::InsertPara, this, mpEditEngine->CreateESelection(aCurSel)); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + aCurSel = mpEditEngine->InsertParaBreak(aCurSel); +} + +void EditHTMLParser::ImpSetAttribs( const SfxItemSet& rItems ) +{ + // pSel, when character attributes, otherwise paragraph attributes for + // the current paragraph. + DBG_ASSERT( aCurSel.Min().GetNode() == aCurSel.Max().GetNode(), "ImpInsertAttribs: Selection?" ); + + EditPaM aStartPaM( aCurSel.Min() ); + EditPaM aEndPaM( aCurSel.Max() ); + + aStartPaM.SetIndex( 0 ); + aEndPaM.SetIndex( aEndPaM.GetNode()->Len() ); + + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + EditSelection aSel( aStartPaM, aEndPaM ); + HtmlImportInfo aImportInfo(HtmlImportState::SetAttr, this, mpEditEngine->CreateESelection(aSel)); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + + ContentNode* pSN = aStartPaM.GetNode(); + sal_Int32 nStartNode = mpEditEngine->GetEditDoc().GetPos( pSN ); + + // If an attribute goes from 0 to current Paragraph length, + // then it should be a paragraph attribute! + + // Note: Selection can reach over several Paragraphs. + // All complete paragraphs are paragraph attributes ... + + // not really HTML: +#ifdef DBG_UTIL + ContentNode* pEN = aEndPaM.GetNode(); + sal_Int32 nEndNode = mpEditEngine->GetEditDoc().GetPos( pEN ); + DBG_ASSERT( nStartNode == nEndNode, "ImpSetAttribs: Several paragraphs?" ); +#endif + + if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) + { + // Has to be merged: + SfxItemSet aItems = mpEditEngine->GetBaseParaAttribs(nStartNode); + aItems.Put( rItems ); + mpEditEngine->SetParaAttribsOnly(nStartNode, aItems); + } + else + mpEditEngine->SetAttribs( EditSelection( aStartPaM, aEndPaM ), rItems ); +} + +void EditHTMLParser::ImpSetStyleSheet( sal_uInt16 nHLevel ) +{ + /* + nHLevel: 0: Turn off + 1-6: Heading + STYLE_PRE: Preformatted + */ + // Create hard attributes ... + // Enough for Calc, would have to be clarified with StyleSheets + // that they should also be in the app so that when they are feed + // in a different engine still are here ... + sal_Int32 nNode = mpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); + + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + + aItems.ClearItem( EE_PARA_ULSPACE ); + + aItems.ClearItem( EE_CHAR_FONTHEIGHT ); + aItems.ClearItem( EE_CHAR_FONTINFO ); + aItems.ClearItem( EE_CHAR_WEIGHT ); + + aItems.ClearItem( EE_CHAR_FONTHEIGHT_CJK ); + aItems.ClearItem( EE_CHAR_FONTINFO_CJK ); + aItems.ClearItem( EE_CHAR_WEIGHT_CJK ); + + aItems.ClearItem( EE_CHAR_FONTHEIGHT_CTL ); + aItems.ClearItem( EE_CHAR_FONTINFO_CTL ); + aItems.ClearItem( EE_CHAR_WEIGHT_CTL ); + + // Bold in the first 3 Headings + if ( ( nHLevel >= 1 ) && ( nHLevel <= 3 ) ) + { + SvxWeightItem aWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ); + aItems.Put( aWeightItem ); + + SvxWeightItem aWeightItemCJK( WEIGHT_BOLD, EE_CHAR_WEIGHT_CJK ); + aItems.Put( aWeightItemCJK ); + + SvxWeightItem aWeightItemCTL( WEIGHT_BOLD, EE_CHAR_WEIGHT_CTL ); + aItems.Put( aWeightItemCTL ); + } + + // Font height and margins, when LogicToLogic is possible: + MapUnit eUnit = mpEditEngine->GetRefMapMode().GetMapUnit(); + if ( ( eUnit != MapUnit::MapPixel ) && ( eUnit != MapUnit::MapSysFont ) && + ( eUnit != MapUnit::MapAppFont ) && ( eUnit != MapUnit::MapRelative ) ) + { + tools::Long nPoints = 10; + if ( nHLevel == 1 ) + nPoints = 22; + else if ( nHLevel == 2 ) + nPoints = 16; + else if ( nHLevel == 3 ) + nPoints = 12; + else if ( nHLevel == 4 ) + nPoints = 11; + + nPoints = OutputDevice::LogicToLogic( nPoints, MapUnit::MapPoint, eUnit ); + + SvxFontHeightItem aHeightItem( nPoints, 100, EE_CHAR_FONTHEIGHT ); + aItems.Put( aHeightItem ); + + SvxFontHeightItem aHeightItemCJK( nPoints, 100, EE_CHAR_FONTHEIGHT_CJK ); + aItems.Put( aHeightItemCJK ); + + SvxFontHeightItem aHeightItemCTL( nPoints, 100, EE_CHAR_FONTHEIGHT_CTL ); + aItems.Put( aHeightItemCTL ); + + // Paragraph margins, when Heading: + if (nHLevel <= 6) + { + SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE ); + aULSpaceItem.SetUpper( static_cast<sal_uInt16>(OutputDevice::LogicToLogic( 42, MapUnit::Map10thMM, eUnit )) ); + aULSpaceItem.SetLower( static_cast<sal_uInt16>(OutputDevice::LogicToLogic( 35, MapUnit::Map10thMM, eUnit )) ); + aItems.Put( aULSpaceItem ); + } + } + + // Choose a proportional Font for Pre + if ( nHLevel == STYLE_PRE ) + { + vcl::Font aFont = OutputDevice::GetDefaultFont( DefaultFontType::FIXED, LANGUAGE_SYSTEM, GetDefaultFontFlags::NONE ); + SvxFontItem aFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(), OUString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO ); + aItems.Put( aFontItem ); + + SvxFontItem aFontItemCJK( aFont.GetFamilyType(), aFont.GetFamilyName(), OUString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO_CJK ); + aItems.Put( aFontItemCJK ); + + SvxFontItem aFontItemCTL( aFont.GetFamilyType(), aFont.GetFamilyName(), OUString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO_CTL ); + aItems.Put( aFontItemCTL ); + } + + mpEditEngine->SetParaAttribsOnly(nNode, aItems); +} + +void EditHTMLParser::ImpInsertText( const OUString& rText ) +{ + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::InsertText, this, mpEditEngine->CreateESelection(aCurSel)); + aImportInfo.aText = rText; + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } + + aCurSel = mpEditEngine->InsertText(aCurSel, rText); +} + +void EditHTMLParser::SkipGroup( HtmlTokenId nEndToken ) +{ + // groups in cells are closed upon leaving the cell, because those + // ******* web authors don't know their job + // for example: <td><form></td> lacks a closing </form> + sal_uInt8 nCellLevel = nInCell; + HtmlTokenId nToken; + while( nCellLevel <= nInCell ) + { + nToken = GetNextToken(); + if (nToken == nEndToken || nToken == HtmlTokenId::NONE) + break; + switch ( nToken ) + { + case HtmlTokenId::TABLEHEADER_ON: + case HtmlTokenId::TABLEDATA_ON: + nInCell++; + break; + case HtmlTokenId::TABLEHEADER_OFF: + case HtmlTokenId::TABLEDATA_OFF: + if ( nInCell ) + nInCell--; + break; + default: break; + } + } +} + +void EditHTMLParser::StartPara( bool bReal ) +{ + if ( bReal ) + { + const HTMLOptions& aOptions = GetOptions(); + SvxAdjust eAdjust = SvxAdjust::Left; + for (const auto & aOption : aOptions) + { + if( aOption.GetToken() == HtmlOptionId::ALIGN ) + { + OUString const& rTmp(aOption.GetString()); + if (rTmp.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_AL_right)) + eAdjust = SvxAdjust::Right; + else if (rTmp.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_AL_middle)) + eAdjust = SvxAdjust::Center; + else if (rTmp.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_AL_center)) + eAdjust = SvxAdjust::Center; + else + eAdjust = SvxAdjust::Left; + } + } + SfxItemSet aItemSet = mpEditEngine->GetEmptyItemSet(); + aItemSet.Put( SvxAdjustItem( eAdjust, EE_PARA_JUST ) ); + ImpSetAttribs( aItemSet ); + } + bInPara = true; +} + +void EditHTMLParser::EndPara() +{ + if ( bInPara ) + { + bool bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + } + bInPara = false; +} + +bool EditHTMLParser::ThrowAwayBlank() +{ + // A blank must be thrown away if the new text begins with a Blank and + // if the current paragraph is empty or ends with a Blank... + ContentNode* pNode = aCurSel.Max().GetNode(); + return !(pNode->Len() && ( pNode->GetChar( pNode->Len()-1 ) != ' ' )); +} + +bool EditHTMLParser::HasTextInCurrentPara() +{ + return aCurSel.Max().GetNode()->Len() != 0; +} + +void EditHTMLParser::AnchorStart() +{ + // ignore anchor in anchor + if ( pCurAnchor ) + return; + + const HTMLOptions& aOptions = GetOptions(); + OUString aRef; + + for (const auto & aOption : aOptions) + { + if( aOption.GetToken() == HtmlOptionId::HREF) + aRef = aOption.GetString(); + } + + if ( aRef.isEmpty() ) + return; + + OUString aURL = aRef; + if ( !aURL.isEmpty() && ( aURL[ 0 ] != '#' ) ) + { + INetURLObject aTargetURL; + INetURLObject aRootURL( aBaseURL ); + aRootURL.GetNewAbsURL( aRef, &aTargetURL ); + aURL = aTargetURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + } + pCurAnchor.reset( new AnchorInfo ); + pCurAnchor->aHRef = aURL; +} + +void EditHTMLParser::AnchorEnd() +{ + if ( !pCurAnchor ) + return; + + // Insert as URL-Field... + SvxFieldItem aFld( SvxURLField( pCurAnchor->aHRef, pCurAnchor->aText, SvxURLFormat::Repr ), EE_FEATURE_FIELD ); + aCurSel = mpEditEngine->InsertField(aCurSel, aFld); + bFieldsInserted = true; + pCurAnchor.reset(); + + if (mpEditEngine->IsHtmlImportHandlerSet()) + { + HtmlImportInfo aImportInfo(HtmlImportState::InsertField, this, mpEditEngine->CreateESelection(aCurSel)); + mpEditEngine->CallHtmlImportHandler(aImportInfo); + } +} + +void EditHTMLParser::HeadingStart( HtmlTokenId nToken ) +{ + bWasInPara = bInPara; + StartPara( false ); + + if ( bWasInPara && HasTextInCurrentPara() ) + ImpInsertParaBreak(); + + sal_uInt16 nId = sal::static_int_cast< sal_uInt16 >( + 1 + ( ( static_cast<int>(nToken) - int(HtmlTokenId::HEAD1_ON) ) / 2 ) ); + DBG_ASSERT( (nId >= 1) && (nId <= 9), "HeadingStart: ID can not be correct!" ); + ImpSetStyleSheet( nId ); +} + +void EditHTMLParser::HeadingEnd() +{ + EndPara(); + ImpSetStyleSheet( 0 ); + + if ( bWasInPara ) + { + bInPara = true; + bWasInPara = false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |