LibreOffice Module sc (master) 1
htmlpars.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <memory>
21#include <sal/config.h>
22
23#include <comphelper/string.hxx>
24
25#include <scitems.hxx>
26
27#include <editeng/colritem.hxx>
28#include <editeng/brushitem.hxx>
29#include <editeng/editeng.hxx>
30#include <editeng/fhgtitem.hxx>
31#include <editeng/fontitem.hxx>
32#include <editeng/postitem.hxx>
33#include <editeng/udlnitem.hxx>
34#include <editeng/wghtitem.hxx>
36#include <editeng/boxitem.hxx>
38#include <sal/log.hxx>
39#include <sfx2/objsh.hxx>
40#include <svl/numformat.hxx>
41#include <svl/intitem.hxx>
42#include <utility>
43#include <vcl/graphicfilter.hxx>
44#include <svtools/parhtml.hxx>
45#include <svtools/htmlkywd.hxx>
46#include <svtools/htmltokn.h>
47
48#include <vcl/outdev.hxx>
49#include <vcl/svapp.hxx>
50#include <tools/urlobj.hxx>
51#include <osl/diagnose.h>
52#include <o3tl/string_view.hxx>
53
54#include <rtl/tencinfo.h>
55
56#include <attrib.hxx>
57#include <htmlpars.hxx>
58#include <global.hxx>
59#include <document.hxx>
60#include <rangelst.hxx>
61
62#include <orcus/css_parser.hpp>
63
64#include <com/sun/star/document/XDocumentProperties.hpp>
65#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
66#include <com/sun/star/frame/XModel.hpp>
67#include <numeric>
68#include <officecfg/Office/Common.hxx>
69
70using ::editeng::SvxBorderLine;
71using namespace ::com::sun::star;
72
74
75void ScHTMLStyles::add(const char* pElemName, size_t nElemName, const char* pClassName, size_t nClassName,
76 const OUString& aProp, const OUString& aValue)
77{
78 if (nElemName)
79 {
80 OUString aElem(pElemName, nElemName, RTL_TEXTENCODING_UTF8);
81 aElem = aElem.toAsciiLowerCase();
82 if (nClassName)
83 {
84 // Both element and class names given.
85 ElemsType::iterator itrElem = m_ElemProps.find(aElem);
86 if (itrElem == m_ElemProps.end())
87 {
88 // new element
89 std::pair<ElemsType::iterator, bool> r =
90 m_ElemProps.insert(std::make_pair(aElem, NamePropsType()));
91 if (!r.second)
92 // insertion failed.
93 return;
94 itrElem = r.first;
95 }
96
97 NamePropsType& rClsProps = itrElem->second;
98 OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
99 aClass = aClass.toAsciiLowerCase();
100 insertProp(rClsProps, aClass, aProp, aValue);
101 }
102 else
103 {
104 // Element name only. Add it to the element global.
105 insertProp(m_ElemGlobalProps, aElem, aProp, aValue);
106 }
107 }
108 else
109 {
110 if (nClassName)
111 {
112 // Class name only. Add it to the global.
113 OUString aClass(pClassName, nClassName, RTL_TEXTENCODING_UTF8);
114 aClass = aClass.toAsciiLowerCase();
115 insertProp(m_GlobalProps, aClass, aProp, aValue);
116 }
117 }
118}
119
121 const OUString& rElem, const OUString& rClass, const OUString& rPropName) const
122{
123 // First, look into the element-class storage.
124 {
125 auto const itr = m_ElemProps.find(rElem);
126 if (itr != m_ElemProps.end())
127 {
128 const NamePropsType& rClasses = itr->second;
129 NamePropsType::const_iterator itr2 = rClasses.find(rClass);
130 if (itr2 != rClasses.end())
131 {
132 const PropsType& rProps = itr2->second;
133 PropsType::const_iterator itr3 = rProps.find(rPropName);
134 if (itr3 != rProps.end())
135 return itr3->second;
136 }
137 }
138 }
139 // Next, look into the class global storage.
140 {
141 auto const itr = m_GlobalProps.find(rClass);
142 if (itr != m_GlobalProps.end())
143 {
144 const PropsType& rProps = itr->second;
145 PropsType::const_iterator itr2 = rProps.find(rPropName);
146 if (itr2 != rProps.end())
147 return itr2->second;
148 }
149 }
150 // As the last resort, look into the element global storage.
151 {
152 auto const itr = m_ElemGlobalProps.find(rClass);
153 if (itr != m_ElemGlobalProps.end())
154 {
155 const PropsType& rProps = itr->second;
156 PropsType::const_iterator itr2 = rProps.find(rPropName);
157 if (itr2 != rProps.end())
158 return itr2->second;
159 }
160 }
161
162 return maEmpty; // nothing found.
163}
164
166 NamePropsType& rStore, const OUString& aName,
167 const OUString& aProp, const OUString& aValue)
168{
169 NamePropsType::iterator itr = rStore.find(aName);
170 if (itr == rStore.end())
171 {
172 // new element
173 std::pair<NamePropsType::iterator, bool> r =
174 rStore.insert(std::make_pair(aName, PropsType()));
175 if (!r.second)
176 // insertion failed.
177 return;
178
179 itr = r.first;
180 }
181
182 PropsType& rProps = itr->second;
183 rProps.emplace(aProp, aValue);
184}
185
186// BASE class for HTML parser classes
187
189 ScEEParser( pEditEngine ),
190 mpDoc( pDoc )
191{
192 maFontHeights[0] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_1::get() * 20;
193 maFontHeights[1] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_2::get() * 20;
194 maFontHeights[2] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_3::get() * 20;
195 maFontHeights[3] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_4::get() * 20;
196 maFontHeights[4] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_5::get() * 20;
197 maFontHeights[5] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_6::get() * 20;
198 maFontHeights[6] = officecfg::Office::Common::Filter::HTML::Import::FontSize::Size_7::get() * 20;
199}
200
202{
203}
204
206 EditEngine* pEditP, OUString _aBaseURL, const Size& aPageSizeP,
207 ScDocument* pDocP ) :
208 ScHTMLParser( pEditP, pDocP ),
209 aPageSize( aPageSizeP ),
210 aBaseURL(std::move( _aBaseURL )),
211 xLockedList( new ScRangeList ),
212 pLocalColOffset( new ScHTMLColOffset ),
213 nFirstTableCell(0),
214 nTableLevel(0),
215 nTable(0),
216 nMaxTable(0),
217 nColCntStart(0),
218 nMaxCol(0),
219 nTableWidth(0),
220 nColOffset(0),
221 nColOffsetStart(0),
222 nOffsetTolerance( SC_HTML_OFFSET_TOLERANCE_SMALL ),
223 bFirstRow( true ),
224 bTabInTabCell( false ),
225 bInCell( false ),
226 bInTitle( false )
227{
228 MakeColNoRef( pLocalColOffset, 0, 0, 0, 0 );
229 MakeColNoRef( &maColOffset, 0, 0, 0, 0 );
230}
231
233{
234 while ( !aTableStack.empty() )
235 {
236 ScHTMLTableStackEntry * pS = aTableStack.top().get();
237 if ( pS->pLocalColOffset != pLocalColOffset )
238 delete pS->pLocalColOffset;
239 aTableStack.pop();
240 }
241 delete pLocalColOffset;
242 if ( pTables )
243 {
244 for( const auto& rEntry : *pTables)
245 delete rEntry.second;
246 pTables.reset();
247 }
248}
249
250ErrCode ScHTMLLayoutParser::Read( SvStream& rStream, const OUString& rBaseURL )
251{
253 pEdit->SetHtmlImportHdl( LINK( this, ScHTMLLayoutParser, HTMLImportHdl ) );
254
256 bool bLoading = pObjSh && pObjSh->IsLoading();
257
258 SvKeyValueIteratorRef xValues;
259 SvKeyValueIterator* pAttributes = nullptr;
260 if ( bLoading )
261 pAttributes = pObjSh->GetHeaderAttributes();
262 else
263 {
264 // When not loading, set up fake http headers to force the SfxHTMLParser to use UTF8
265 // (used when pasting from clipboard)
266 const char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
267 if( pCharSet )
268 {
269 OUString aContentType = "text/html; charset=" +
270 OUString::createFromAscii( pCharSet );
271
272 xValues = new SvKeyValueIterator;
273 xValues->Append( SvKeyValue( OOO_STRING_SVTOOLS_HTML_META_content_type, aContentType ) );
274 pAttributes = xValues.get();
275 }
276 }
277
278 ErrCode nErr = pEdit->Read( rStream, rBaseURL, EETextFormat::Html, pAttributes );
279
280 pEdit->SetHtmlImportHdl( aOldLink );
281 // Create column width
282 Adjust();
284 sal_uInt16 nCount = maColOffset.size();
285 sal_uLong nOff = maColOffset[0];
286 Size aSize;
287 for ( sal_uInt16 j = 1; j < nCount; j++ )
288 {
289 aSize.setWidth( maColOffset[j] - nOff );
290 aSize = pDefaultDev->PixelToLogic( aSize, MapMode( MapUnit::MapTwip ) );
291 maColWidths[ j-1 ] = aSize.Width();
292 nOff = maColOffset[j];
293 }
294 return nErr;
295}
296
298{
299 return nullptr;
300}
301
303{
305 if ( pE )
306 {
307 if ( !pE->aSel.HasRange() )
308 { // Completely empty, following text ends up in the same paragraph!
309 mxActEntry->aSel.nStartPara = pE->aSel.nEndPara;
310 mxActEntry->aSel.nStartPos = pE->aSel.nEndPos;
311 }
312 }
313 mxActEntry->aSel.nEndPara = mxActEntry->aSel.nStartPara;
314 mxActEntry->aSel.nEndPos = mxActEntry->aSel.nStartPos;
315}
316
318{
319 if ( rSel.nEndPara >= pE->aSel.nStartPara )
320 {
321 pE->aSel.nEndPara = rSel.nEndPara;
322 pE->aSel.nEndPos = rSel.nEndPos;
323 }
324 else if ( rSel.nStartPara == pE->aSel.nStartPara - 1 && !pE->aSel.HasRange() )
325 { // Did not attach a paragraph, but empty, do nothing
326 }
327 else
328 {
329 OSL_FAIL( "EntryEnd: EditEngine ESelection End < Start" );
330 }
331}
332
334{
335 if ( bInCell )
336 CloseEntry( pInfo );
337 if ( nRowMax < ++nRowCnt )
341 bFirstRow = false;
342}
343
344bool ScHTMLLayoutParser::SeekOffset( const ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
345 SCCOL* pCol, sal_uInt16 nOffsetTol )
346{
347 OSL_ENSURE( pOffset, "ScHTMLLayoutParser::SeekOffset - illegal call" );
348 ScHTMLColOffset::const_iterator it = pOffset->find( nOffset );
349 bool bFound = it != pOffset->end();
350 sal_uInt16 nPos = it - pOffset->begin();
351 *pCol = static_cast<SCCOL>(nPos);
352 if ( bFound )
353 return true;
354 sal_uInt16 nCount = pOffset->size();
355 if ( !nCount )
356 return false;
357 // nPos is the position of insertion, that's where the next higher one is (or isn't)
358 if ( nPos < nCount && (((*pOffset)[nPos] - nOffsetTol) <= nOffset) )
359 return true;
360 // Not smaller than everything else? Then compare with the next lower one
361 else if ( nPos && (((*pOffset)[nPos-1] + nOffsetTol) >= nOffset) )
362 {
363 (*pCol)--;
364 return true;
365 }
366 return false;
367}
368
369void ScHTMLLayoutParser::MakeCol( ScHTMLColOffset* pOffset, sal_uInt16& nOffset,
370 sal_uInt16& nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
371{
372 OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeCol - illegal call" );
373 SCCOL nPos;
374 if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
375 nOffset = static_cast<sal_uInt16>((*pOffset)[nPos]);
376 else
377 pOffset->insert( nOffset );
378 if ( nWidth )
379 {
380 if ( SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
381 nWidth = static_cast<sal_uInt16>((*pOffset)[nPos]) - nOffset;
382 else
383 pOffset->insert( nOffset + nWidth );
384 }
385}
386
387void ScHTMLLayoutParser::MakeColNoRef( ScHTMLColOffset* pOffset, sal_uInt16 nOffset,
388 sal_uInt16 nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol )
389{
390 OSL_ENSURE( pOffset, "ScHTMLLayoutParser::MakeColNoRef - illegal call" );
391 SCCOL nPos;
392 if ( SeekOffset( pOffset, nOffset, &nPos, nOffsetTol ) )
393 nOffset = static_cast<sal_uInt16>((*pOffset)[nPos]);
394 else
395 pOffset->insert( nOffset );
396 if ( nWidth )
397 {
398 if ( !SeekOffset( pOffset, nOffset + nWidth, &nPos, nWidthTol ) )
399 pOffset->insert( nOffset + nWidth );
400 }
401}
402
403void ScHTMLLayoutParser::ModifyOffset( ScHTMLColOffset* pOffset, sal_uInt16& nOldOffset,
404 sal_uInt16& nNewOffset, sal_uInt16 nOffsetTol )
405{
406 OSL_ENSURE( pOffset, "ScHTMLLayoutParser::ModifyOffset - illegal call" );
407 SCCOL nPos;
408 if ( !SeekOffset( pOffset, nOldOffset, &nPos, nOffsetTol ) )
409 {
410 if ( SeekOffset( pOffset, nNewOffset, &nPos, nOffsetTol ) )
411 nNewOffset = static_cast<sal_uInt16>((*pOffset)[nPos]);
412 else
413 pOffset->insert( nNewOffset );
414 return ;
415 }
416 nOldOffset = static_cast<sal_uInt16>((*pOffset)[nPos]);
417 SCCOL nPos2;
418 if ( SeekOffset( pOffset, nNewOffset, &nPos2, nOffsetTol ) )
419 {
420 nNewOffset = static_cast<sal_uInt16>((*pOffset)[nPos2]);
421 return ;
422 }
423 tools::Long nDiff = nNewOffset - nOldOffset;
424 if ( nDiff < 0 )
425 {
426 do
427 {
428 const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
429 } while ( nPos-- );
430 }
431 else
432 {
433 do
434 {
435 const_cast<sal_uLong&>((*pOffset)[nPos]) += nDiff;
436 } while ( ++nPos < static_cast<sal_uInt16>(pOffset->size()) );
437 }
438}
439
441{
442 if ( !mpDoc->ValidCol(pE->nCol) )
443 return;
444
445// Or else this would create a wrong value at ScAddress (chance for an infinite loop)!
446 bool bBadCol = false;
447 bool bAgain;
448 ScRange aRange( pE->nCol, pE->nRow, 0,
449 pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 );
450 do
451 {
452 bAgain = false;
453 for ( size_t i = 0, nRanges = xLockedList->size(); i < nRanges; ++i )
454 {
455 ScRange & rR = (*xLockedList)[i];
456 if ( rR.Intersects( aRange ) )
457 {
458 pE->nCol = rR.aEnd.Col() + 1;
459 SCCOL nTmp = pE->nCol + pE->nColOverlap - 1;
460 if ( pE->nCol > mpDoc->MaxCol() || nTmp > mpDoc->MaxCol() )
461 bBadCol = true;
462 else
463 {
464 bAgain = true;
465 aRange.aStart.SetCol( pE->nCol );
466 aRange.aEnd.SetCol( nTmp );
467 }
468 break;
469 }
470 }
471 } while ( bAgain );
472 if ( bJoin && !bBadCol )
473 xLockedList->Join( aRange );
474}
475
477{
478 xLockedList->RemoveAll();
479
480 std::stack< std::unique_ptr<ScHTMLAdjustStackEntry> > aStack;
481 sal_uInt16 nTab = 0;
482 SCCOL nLastCol = SCCOL_MAX;
483 SCROW nNextRow = 0;
484 SCROW nCurRow = 0;
485 sal_uInt16 nPageWidth = static_cast<sal_uInt16>(aPageSize.Width());
486 InnerMap* pTab = nullptr;
487 for (auto& pE : maList)
488 {
489 if ( pE->nTab < nTab )
490 { // Table finished
491 if ( !aStack.empty() )
492 {
493 std::unique_ptr<ScHTMLAdjustStackEntry> pS = std::move(aStack.top());
494 aStack.pop();
495
496 nLastCol = pS->nLastCol;
497 nNextRow = pS->nNextRow;
498 nCurRow = pS->nCurRow;
499 }
500 nTab = pE->nTab;
501 if (pTables)
502 {
503 OuterMap::const_iterator it = pTables->find( nTab );
504 if ( it != pTables->end() )
505 pTab = it->second;
506 }
507
508 }
509 SCROW nRow = pE->nRow;
510 if ( pE->nCol <= nLastCol )
511 { // Next row
512 if ( pE->nRow < nNextRow )
513 pE->nRow = nCurRow = nNextRow;
514 else
515 nCurRow = nNextRow = pE->nRow;
516 SCROW nR = 0;
517 if ( pTab )
518 {
519 InnerMap::const_iterator it = pTab->find( nCurRow );
520 if ( it != pTab->end() )
521 nR = it->second;
522 }
523 if ( nR )
524 nNextRow += nR;
525 else
526 nNextRow++;
527 }
528 else
529 pE->nRow = nCurRow;
530 nLastCol = pE->nCol; // Read column
531 if ( pE->nTab > nTab )
532 { // New table
533 aStack.push( std::make_unique<ScHTMLAdjustStackEntry>(
534 nLastCol, nNextRow, nCurRow ) );
535 nTab = pE->nTab;
536 if ( pTables )
537 {
538 OuterMap::const_iterator it = pTables->find( nTab );
539 if ( it != pTables->end() )
540 pTab = it->second;
541 }
542 // New line spacing
543 SCROW nR = 0;
544 if ( pTab )
545 {
546 InnerMap::const_iterator it = pTab->find( nCurRow );
547 if ( it != pTab->end() )
548 nR = it->second;
549 }
550 if ( nR )
551 nNextRow = nCurRow + nR;
552 else
553 nNextRow = nCurRow + 1;
554 }
555 if ( nTab == 0 )
556 pE->nWidth = nPageWidth;
557 else
558 { // Real table, no paragraphs on the field
559 if ( pTab )
560 {
561 SCROW nRowSpan = pE->nRowOverlap;
562 for ( SCROW j=0; j < nRowSpan; j++ )
563 { // RowSpan resulting from merged rows
564 SCROW nRows = 0;
565 InnerMap::const_iterator it = pTab->find( nRow+j );
566 if ( it != pTab->end() )
567 nRows = it->second;
568 if ( nRows > 1 )
569 {
570 pE->nRowOverlap += nRows - 1;
571 if ( j == 0 )
572 { // Merged rows move the next row
573 SCROW nTmp = nCurRow + nRows;
574 if ( nNextRow < nTmp )
575 nNextRow = nTmp;
576 }
577 }
578 }
579 }
580 }
581 // Real column
582 (void)SeekOffset( &maColOffset, pE->nOffset, &pE->nCol, nOffsetTolerance );
583 SCCOL nColBeforeSkip = pE->nCol;
584 SkipLocked(pE.get(), false);
585 if ( pE->nCol != nColBeforeSkip )
586 {
587 SCCOL nCount = static_cast<SCCOL>(maColOffset.size());
588 if ( nCount <= pE->nCol )
589 {
590 pE->nOffset = static_cast<sal_uInt16>(maColOffset[nCount-1]);
591 MakeCol( &maColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
592 }
593 else
594 {
595 pE->nOffset = static_cast<sal_uInt16>(maColOffset[pE->nCol]);
596 }
597 }
598 SCCOL nPos;
599 if ( pE->nWidth && SeekOffset( &maColOffset, pE->nOffset + pE->nWidth, &nPos, nOffsetTolerance ) )
600 pE->nColOverlap = (nPos > pE->nCol ? nPos - pE->nCol : 1);
601 else
602 {
603 //FIXME: This may not be correct, but works anyway ...
604 pE->nColOverlap = 1;
605 }
606 xLockedList->Join( ScRange( pE->nCol, pE->nRow, 0,
607 pE->nCol + pE->nColOverlap - 1, pE->nRow + pE->nRowOverlap - 1, 0 ) );
608 // Take over MaxDimensions
609 SCCOL nColTmp = pE->nCol + pE->nColOverlap;
610 if ( nColMax < nColTmp )
611 nColMax = nColTmp;
612 SCROW nRowTmp = pE->nRow + pE->nRowOverlap;
613 if ( nRowMax < nRowTmp )
614 nRowMax = nRowTmp;
615 }
616}
617
619{
620 if ( pE->nWidth )
621 return pE->nWidth;
622 sal_Int32 nTmp = std::min( static_cast<sal_Int32>( pE->nCol -
623 nColCntStart + pE->nColOverlap),
624 static_cast<sal_Int32>( pLocalColOffset->size() - 1));
625 SCCOL nPos = (nTmp < 0 ? 0 : static_cast<SCCOL>(nTmp));
626 sal_uInt16 nOff2 = static_cast<sal_uInt16>((*pLocalColOffset)[nPos]);
627 if ( pE->nOffset < nOff2 )
628 return nOff2 - pE->nOffset;
629 return 0;
630}
631
633{
634 SCCOL nCol;
635 if ( !nTableWidth )
636 nTableWidth = static_cast<sal_uInt16>(aPageSize.Width());
637 SCCOL nColsPerRow = nMaxCol - nColCntStart;
638 if ( nColsPerRow <= 0 )
639 nColsPerRow = 1;
640 if ( pLocalColOffset->size() <= 2 )
641 { // Only PageSize, there was no width setting
642 sal_uInt16 nWidth = nTableWidth / static_cast<sal_uInt16>(nColsPerRow);
643 sal_uInt16 nOff = nColOffsetStart;
645 for ( nCol = 0; nCol <= nColsPerRow; ++nCol, nOff = nOff + nWidth )
646 {
647 MakeColNoRef( pLocalColOffset, nOff, 0, 0, 0 );
648 }
649 nTableWidth = static_cast<sal_uInt16>(pLocalColOffset->back() - pLocalColOffset->front());
650 for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
651 {
652 auto& pE = maList[ i ];
653 if ( pE->nTab == nTable )
654 {
655 pE->nOffset = static_cast<sal_uInt16>((*pLocalColOffset)[pE->nCol - nColCntStart]);
656 pE->nWidth = 0; // to be recalculated later
657 }
658 }
659 }
660 else
661 { // Some without width
662 // Why actually no pE?
663 if ( nFirstTableCell < maList.size() )
664 {
665 std::unique_ptr<sal_uInt16[]> pOffsets(new sal_uInt16[ nColsPerRow+1 ]);
666 memset( pOffsets.get(), 0, (nColsPerRow+1) * sizeof(sal_uInt16) );
667 std::unique_ptr<sal_uInt16[]> pWidths(new sal_uInt16[ nColsPerRow ]);
668 memset( pWidths.get(), 0, nColsPerRow * sizeof(sal_uInt16) );
669 pOffsets[0] = nColOffsetStart;
670 for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
671 {
672 auto& pE = maList[ i ];
673 if ( pE->nTab == nTable && pE->nWidth )
674 {
675 nCol = pE->nCol - nColCntStart;
676 if ( nCol < nColsPerRow )
677 {
678 if ( pE->nColOverlap == 1 )
679 {
680 if ( pWidths[nCol] < pE->nWidth )
681 pWidths[nCol] = pE->nWidth;
682 }
683 else
684 { // try to find a single undefined width
685 sal_uInt16 nTotal = 0;
686 bool bFound = false;
687 SCCOL nHere = 0;
688 SCCOL nStop = std::min( static_cast<SCCOL>(nCol + pE->nColOverlap), nColsPerRow );
689 for ( ; nCol < nStop; nCol++ )
690 {
691 if ( pWidths[nCol] )
692 nTotal = nTotal + pWidths[nCol];
693 else
694 {
695 if ( bFound )
696 {
697 bFound = false;
698 break; // for
699 }
700 bFound = true;
701 nHere = nCol;
702 }
703 }
704 if ( bFound && pE->nWidth > nTotal )
705 pWidths[nHere] = pE->nWidth - nTotal;
706 }
707 }
708 }
709 }
710 sal_uInt16 nWidths = 0;
711 sal_uInt16 nUnknown = 0;
712 for ( nCol = 0; nCol < nColsPerRow; nCol++ )
713 {
714 if ( pWidths[nCol] )
715 nWidths = nWidths + pWidths[nCol];
716 else
717 nUnknown++;
718 }
719 if ( nUnknown )
720 {
721 sal_uInt16 nW = ((nWidths < nTableWidth) ?
722 ((nTableWidth - nWidths) / nUnknown) :
723 (nTableWidth / nUnknown));
724 for ( nCol = 0; nCol < nColsPerRow; nCol++ )
725 {
726 if ( !pWidths[nCol] )
727 pWidths[nCol] = nW;
728 }
729 }
730 for ( nCol = 1; nCol <= nColsPerRow; nCol++ )
731 {
732 pOffsets[nCol] = pOffsets[nCol-1] + pWidths[nCol-1];
733 }
735 for ( nCol = 0; nCol <= nColsPerRow; nCol++ )
736 {
737 MakeColNoRef( pLocalColOffset, pOffsets[nCol], 0, 0, 0 );
738 }
739 nTableWidth = pOffsets[nColsPerRow] - pOffsets[0];
740
741 for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
742 {
743 auto& pE = maList[ i ];
744 if ( pE->nTab == nTable )
745 {
746 nCol = pE->nCol - nColCntStart;
747 OSL_ENSURE( nCol < nColsPerRow, "ScHTMLLayoutParser::SetWidths: column overflow" );
748 if ( nCol < nColsPerRow )
749 {
750 pE->nOffset = pOffsets[nCol];
751 nCol = nCol + pE->nColOverlap;
752 if ( nCol > nColsPerRow )
753 nCol = nColsPerRow;
754 pE->nWidth = pOffsets[nCol] - pE->nOffset;
755 }
756 }
757 }
758 }
759 }
760 if ( !pLocalColOffset->empty() )
761 {
762 sal_uInt16 nMax = static_cast<sal_uInt16>(pLocalColOffset->back());
763 if ( aPageSize.Width() < nMax )
764 aPageSize.setWidth( nMax );
765 if (nTableLevel == 0)
766 {
767 // Local table is very outer table, create missing offsets.
768 for (auto it = pLocalColOffset->begin(); it != pLocalColOffset->end(); ++it)
769 {
770 // Only exact offsets, do not use MakeColNoRef().
771 maColOffset.insert(*it);
772 }
773 }
774 }
775 for ( size_t i = nFirstTableCell, nListSize = maList.size(); i < nListSize; ++i )
776 {
777 auto& pE = maList[ i ];
778 if ( pE->nTab == nTable )
779 {
780 if ( !pE->nWidth )
781 {
782 pE->nWidth = GetWidth(pE.get());
783 OSL_ENSURE( pE->nWidth, "SetWidths: pE->nWidth == 0" );
784 }
785 MakeCol( &maColOffset, pE->nOffset, pE->nWidth, nOffsetTolerance, nOffsetTolerance );
786 }
787 }
788}
789
791{
792 if ( pE->nCol == SCCOL_MAX )
793 pE->nCol = nColCnt;
794 if ( pE->nRow == SCROW_MAX )
795 pE->nRow = nRowCnt;
796 SCCOL nCol = pE->nCol;
797 SkipLocked( pE ); // Change of columns to the right
798
799 if ( nCol < pE->nCol )
800 { // Replaced
801 nCol = pE->nCol - nColCntStart;
802 SCCOL nCount = static_cast<SCCOL>(pLocalColOffset->size());
803 if ( nCol < nCount )
804 nColOffset = static_cast<sal_uInt16>((*pLocalColOffset)[nCol]);
805 else
806 nColOffset = static_cast<sal_uInt16>((*pLocalColOffset)[nCount - 1]);
807 }
808 pE->nOffset = nColOffset;
809 sal_uInt16 nWidth = GetWidth( pE );
811 if ( pE->nWidth )
812 pE->nWidth = nWidth;
813 nColOffset = pE->nOffset + nWidth;
816}
817
819{
820 bInCell = false;
821 if ( bTabInTabCell )
822 { // From the stack in TableOff
823 bTabInTabCell = false;
824 NewActEntry(maList.back().get()); // New free flying mxActEntry
825 return ;
826 }
827 if (mxActEntry->nTab == 0)
828 mxActEntry->nWidth = static_cast<sal_uInt16>(aPageSize.Width());
829 Colonize(mxActEntry.get());
830 nColCnt = mxActEntry->nCol + mxActEntry->nColOverlap;
831 if ( nMaxCol < nColCnt )
832 nMaxCol = nColCnt; // TableStack MaxCol
833 if ( nColMax < nColCnt )
834 nColMax = nColCnt; // Global MaxCol for ScEEParser GetDimensions!
835 EntryEnd(mxActEntry.get(), pInfo->aSelection);
836 ESelection& rSel = mxActEntry->aSel;
837 while ( rSel.nStartPara < rSel.nEndPara
838 && pEdit->GetTextLen( rSel.nStartPara ) == 0 )
839 { // Strip preceding empty paragraphs
840 rSel.nStartPara++;
841 }
842 while ( rSel.nEndPos == 0 && rSel.nEndPara > rSel.nStartPara )
843 { // Strip successive empty paragraphs
844 rSel.nEndPara--;
845 rSel.nEndPos = pEdit->GetTextLen( rSel.nEndPara );
846 }
847 if ( rSel.nStartPara > rSel.nEndPara )
848 { // Gives GPF in CreateTextObject
849 OSL_FAIL( "CloseEntry: EditEngine ESelection Start > End" );
850 rSel.nEndPara = rSel.nStartPara;
851 }
852 if ( rSel.HasRange() )
853 mxActEntry->aItemSet.Put( ScLineBreakCell(true) );
854 maList.push_back(mxActEntry);
855 NewActEntry(mxActEntry.get()); // New free flying mxActEntry
856}
857
858IMPL_LINK( ScHTMLLayoutParser, HTMLImportHdl, HtmlImportInfo&, rInfo, void )
859{
860 switch ( rInfo.eState )
861 {
862 case HtmlImportState::NextToken:
863 ProcToken( &rInfo );
864 break;
865 case HtmlImportState::Start:
866 break;
867 case HtmlImportState::End:
868 if ( rInfo.aSelection.nEndPos )
869 {
870 // If text remains: create paragraph, without calling CloseEntry().
871 if( bInCell ) // ...but only in opened table cells.
872 {
873 bInCell = false;
874 NextRow( &rInfo );
875 bInCell = true;
876 }
877 CloseEntry( &rInfo );
878 }
879 while ( nTableLevel > 0 )
880 TableOff( &rInfo ); // close tables, if </TABLE> missing
881 break;
882 case HtmlImportState::SetAttr:
883 break;
884 case HtmlImportState::InsertText:
885 break;
886 case HtmlImportState::InsertPara:
887 if ( nTableLevel < 1 )
888 {
889 CloseEntry( &rInfo );
890 NextRow( &rInfo );
891 }
892 break;
893 case HtmlImportState::InsertField:
894 break;
895 default:
896 OSL_FAIL("HTMLImportHdl: unknown ImportInfo.eState");
897 }
898}
899
901{
902 if ( bInCell )
903 CloseEntry( pInfo );
904 if ( !nTableLevel )
905 {
906 OSL_FAIL( "dumbo doc! <TH> or <TD> without previous <TABLE>" );
907 TableOn( pInfo );
908 }
909 bInCell = true;
910 bool bHorJustifyCenterTH = (pInfo->nToken == HtmlTokenId::TABLEHEADER_ON);
911 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
912 for (const auto & rOption : rOptions)
913 {
914 switch( rOption.GetToken() )
915 {
916 case HtmlOptionId::COLSPAN:
917 {
918 mxActEntry->nColOverlap = static_cast<SCCOL>(rOption.GetString().toInt32());
919 }
920 break;
921 case HtmlOptionId::ROWSPAN:
922 {
923 mxActEntry->nRowOverlap = static_cast<SCROW>(rOption.GetString().toInt32());
924 }
925 break;
926 case HtmlOptionId::ALIGN:
927 {
928 bHorJustifyCenterTH = false;
930 const OUString& rOptVal = rOption.GetString();
931 if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
932 eVal = SvxCellHorJustify::Right;
933 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
934 eVal = SvxCellHorJustify::Center;
935 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
936 eVal = SvxCellHorJustify::Left;
937 else
938 eVal = SvxCellHorJustify::Standard;
939 if ( eVal != SvxCellHorJustify::Standard )
940 mxActEntry->aItemSet.Put(SvxHorJustifyItem(eVal, ATTR_HOR_JUSTIFY));
941 }
942 break;
943 case HtmlOptionId::VALIGN:
944 {
946 const OUString& rOptVal = rOption.GetString();
947 if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
948 eVal = SvxCellVerJustify::Top;
949 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
950 eVal = SvxCellVerJustify::Center;
951 else if ( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
952 eVal = SvxCellVerJustify::Bottom;
953 else
954 eVal = SvxCellVerJustify::Standard;
955 mxActEntry->aItemSet.Put(SvxVerJustifyItem(eVal, ATTR_VER_JUSTIFY));
956 }
957 break;
958 case HtmlOptionId::WIDTH:
959 {
960 mxActEntry->nWidth = GetWidthPixel(rOption);
961 }
962 break;
963 case HtmlOptionId::BGCOLOR:
964 {
965 Color aColor;
966 rOption.GetColor( aColor );
967 mxActEntry->aItemSet.Put(SvxBrushItem(aColor, ATTR_BACKGROUND));
968 }
969 break;
970 case HtmlOptionId::SDVAL:
971 {
972 mxActEntry->pValStr = rOption.GetString();
973 }
974 break;
975 case HtmlOptionId::SDNUM:
976 {
977 mxActEntry->pNumStr = rOption.GetString();
978 }
979 break;
980 default: break;
981 }
982 }
983
984 mxActEntry->nCol = nColCnt;
985 mxActEntry->nRow = nRowCnt;
986 mxActEntry->nTab = nTable;
987
988 if ( bHorJustifyCenterTH )
989 mxActEntry->aItemSet.Put(
990 SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY) );
991}
992
994{
995 if ( nColCnt > nColCntStart )
996 NextRow( pInfo ); // The optional TableRowOff wasn't there
998}
999
1001{
1002 NextRow( pInfo );
1003}
1004
1006{
1007 if ( bInCell )
1008 CloseEntry( pInfo ); // Only if it really was one
1009}
1010
1012{
1013 if ( ++nTableLevel > 1 )
1014 { // Table in Table
1015 sal_uInt16 nTmpColOffset = nColOffset; // Will be changed in Colonize()
1016 Colonize(mxActEntry.get());
1017 aTableStack.push( std::make_unique<ScHTMLTableStackEntry>(
1021 bFirstRow ) );
1022 sal_uInt16 nLastWidth = nTableWidth;
1024 if ( nTableWidth == nLastWidth && nMaxCol - nColCntStart > 1 )
1025 { // There must be more than one, so this one cannot be enough
1026 nTableWidth = nLastWidth / static_cast<sal_uInt16>((nMaxCol - nColCntStart));
1027 }
1028 nLastWidth = nTableWidth;
1029 if ( pInfo->nToken == HtmlTokenId::TABLE_ON )
1030 { // It can still be TD or TH, if we didn't have a TABLE earlier
1031 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1032 for (const auto & rOption : rOptions)
1033 {
1034 switch( rOption.GetToken() )
1035 {
1036 case HtmlOptionId::WIDTH:
1037 { // Percent: of document width or outer cell
1038 nTableWidth = GetWidthPixel( rOption );
1039 }
1040 break;
1041 case HtmlOptionId::BORDER:
1042 // Border is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
1043 break;
1044 default: break;
1045 }
1046 }
1047 }
1048 bInCell = false;
1049 if ( bTabInTabCell && (nTableWidth >= nLastWidth) )
1050 { // Multiple tables in one cell, underneath each other
1051 bTabInTabCell = false;
1052 NextRow( pInfo );
1053 }
1054 else
1055 { // It start's in this cell or next to each other
1056 bTabInTabCell = false;
1058 nColOffset = nTmpColOffset;
1060 }
1061
1062 NewActEntry(!maList.empty() ? maList.back().get() : nullptr); // New free flying mxActEntry
1064 }
1065 else
1066 { // Simple table at the document level
1067 EntryEnd(mxActEntry.get(), pInfo->aSelection);
1068 if (mxActEntry->aSel.HasRange())
1069 { // Flying text left
1070 CloseEntry( pInfo );
1071 NextRow( pInfo );
1072 }
1073 aTableStack.push( std::make_unique<ScHTMLTableStackEntry>(
1077 bFirstRow ) );
1078 // As soon as we have multiple tables we need to be tolerant with the offsets.
1079 if (nMaxTable > 0)
1081 nTableWidth = 0;
1082 if ( pInfo->nToken == HtmlTokenId::TABLE_ON )
1083 {
1084 // It can still be TD or TH, if we didn't have a TABLE earlier
1085 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1086 for (const auto & rOption : rOptions)
1087 {
1088 switch( rOption.GetToken() )
1089 {
1090 case HtmlOptionId::WIDTH:
1091 { // Percent: of document width or outer cell
1092 nTableWidth = GetWidthPixel( rOption );
1093 }
1094 break;
1095 case HtmlOptionId::BORDER:
1096 //BorderOn is: ((pOption->GetString().Len() == 0) || (pOption->GetNumber() != 0));
1097 break;
1098 default: break;
1099 }
1100 }
1101 }
1102 }
1103 nTable = ++nMaxTable;
1104 bFirstRow = true;
1105 nFirstTableCell = maList.size();
1106
1109}
1110
1112{
1113 if ( bInCell )
1114 CloseEntry( pInfo );
1115 if ( nColCnt > nColCntStart )
1116 TableRowOff( pInfo ); // The optional TableRowOff wasn't
1117 if ( !nTableLevel )
1118 {
1119 OSL_FAIL( "dumbo doc! </TABLE> without opening <TABLE>" );
1120 return ;
1121 }
1122 if ( --nTableLevel > 0 )
1123 { // Table in Table done
1124 if ( !aTableStack.empty() )
1125 {
1126 std::unique_ptr<ScHTMLTableStackEntry> pS = std::move(aTableStack.top());
1127 aTableStack.pop();
1128
1129 auto& pE = pS->xCellEntry;
1130 SCROW nRows = nRowCnt - pS->nRowCnt;
1131 if ( nRows > 1 )
1132 { // Insert size of table at this position
1133 SCROW nRow = pS->nRowCnt;
1134 sal_uInt16 nTab = pS->nTable;
1135 if ( !pTables )
1136 pTables.reset( new OuterMap );
1137 // Height of outer table
1138 OuterMap::const_iterator it = pTables->find( nTab );
1139 InnerMap* pTab1;
1140 if ( it == pTables->end() )
1141 {
1142 pTab1 = new InnerMap;
1143 (*pTables)[ nTab ] = pTab1;
1144 }
1145 else
1146 pTab1 = it->second;
1147 SCROW nRowSpan = pE->nRowOverlap;
1148 SCROW nRowKGV;
1149 SCROW nRowsPerRow1; // Outer table
1150 SCROW nRowsPerRow2; // Inner table
1151 if ( nRowSpan > 1 )
1152 { // LCM to which we can map the inner and outer rows
1153 nRowKGV = std::lcm( nRowSpan, nRows );
1154 nRowsPerRow1 = nRowKGV / nRowSpan;
1155 nRowsPerRow2 = nRowKGV / nRows;
1156 }
1157 else
1158 {
1159 nRowKGV = nRowsPerRow1 = nRows;
1160 nRowsPerRow2 = 1;
1161 }
1162 InnerMap* pTab2 = nullptr;
1163 if ( nRowsPerRow2 > 1 )
1164 { // Height of the inner table
1165 pTab2 = new InnerMap;
1166 (*pTables)[ nTable ] = pTab2;
1167 }
1168 // Abuse void* Data entry of the Table class for height mapping
1169 if ( nRowKGV > 1 )
1170 {
1171 if ( nRowsPerRow1 > 1 )
1172 { // Outer
1173 for ( SCROW j=0; j < nRowSpan; j++ )
1174 {
1175 sal_uLong nRowKey = nRow + j;
1176 SCROW nR = (*pTab1)[ nRowKey ];
1177 if ( !nR )
1178 (*pTab1)[ nRowKey ] = nRowsPerRow1;
1179 else if ( nRowsPerRow1 > nR )
1180 (*pTab1)[ nRowKey ] = nRowsPerRow1;
1181 //TODO: How can we improve on this?
1182 else if ( nRowsPerRow1 < nR && nRowSpan == 1
1183 && nTable == nMaxTable )
1184 { // Still some space left, merge in a better way (if possible)
1185 SCROW nAdd = nRowsPerRow1 - (nR % nRowsPerRow1);
1186 nR += nAdd;
1187 if ( (nR % nRows) == 0 )
1188 { // Only if representable
1189 SCROW nR2 = (*pTab1)[ nRowKey+1 ];
1190 if ( nR2 > nAdd )
1191 { // Only if we really have enough space
1192 (*pTab1)[ nRowKey ] = nR;
1193 (*pTab1)[ nRowKey+1 ] = nR2 - nAdd;
1194 nRowsPerRow2 = nR / nRows;
1195 }
1196 }
1197 }
1198 }
1199 }
1200 if ( nRowsPerRow2 > 1 )
1201 { // Inner
1202 if ( !pTab2 )
1203 { // nRowsPerRow2 could be've been incremented
1204 pTab2 = new InnerMap;
1205 (*pTables)[ nTable ] = pTab2;
1206 }
1207 for ( SCROW j=0; j < nRows; j++ )
1208 {
1209 sal_uLong nRowKey = nRow + j;
1210 (*pTab2)[ nRowKey ] = nRowsPerRow2;
1211 }
1212 }
1213 }
1214 }
1215
1216 SetWidths();
1217
1218 if ( !pE->nWidth )
1219 pE->nWidth = nTableWidth;
1220 else if ( pE->nWidth < nTableWidth )
1221 {
1222 sal_uInt16 nOldOffset = pE->nOffset + pE->nWidth;
1223 sal_uInt16 nNewOffset = pE->nOffset + nTableWidth;
1224 ModifyOffset( pS->pLocalColOffset, nOldOffset, nNewOffset, nOffsetTolerance );
1225 sal_uInt16 nTmp = nNewOffset - pE->nOffset - pE->nWidth;
1226 pE->nWidth = nNewOffset - pE->nOffset;
1227 pS->nTableWidth = pS->nTableWidth + nTmp;
1228 if ( pS->nColOffset >= nOldOffset )
1229 pS->nColOffset = pS->nColOffset + nTmp;
1230 }
1231
1232 nColCnt = pE->nCol + pE->nColOverlap;
1233 nRowCnt = pS->nRowCnt;
1234 nColCntStart = pS->nColCntStart;
1235 nMaxCol = pS->nMaxCol;
1236 nTable = pS->nTable;
1237 nTableWidth = pS->nTableWidth;
1238 nFirstTableCell = pS->nFirstTableCell;
1239 nColOffset = pS->nColOffset;
1240 nColOffsetStart = pS->nColOffsetStart;
1241 bFirstRow = pS->bFirstRow;
1242 xLockedList = pS->xLockedList;
1243 pLocalColOffset = pS->pLocalColOffset;
1244 // mxActEntry is kept around if a table is started in the same row
1245 // (anything's possible in HTML); will be deleted by CloseEntry
1246 mxActEntry = pE;
1247 }
1248 bTabInTabCell = true;
1249 bInCell = true;
1250 }
1251 else
1252 { // Simple table finished
1253 SetWidths();
1254 nMaxCol = 0;
1255 nTable = 0;
1256 if ( !aTableStack.empty() )
1257 {
1258 ScHTMLTableStackEntry* pS = aTableStack.top().get();
1259 delete pLocalColOffset;
1260 pLocalColOffset = pS->pLocalColOffset;
1261 aTableStack.pop();
1262 }
1263 }
1264}
1265
1267{
1268 mxActEntry->maImageList.push_back(std::make_unique<ScHTMLImage>());
1269 ScHTMLImage* pImage = mxActEntry->maImageList.back().get();
1270 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1271 for (const auto & rOption : rOptions)
1272 {
1273 switch( rOption.GetToken() )
1274 {
1275 case HtmlOptionId::SRC:
1276 {
1277 pImage->aURL = INetURLObject::GetAbsURL( aBaseURL, rOption.GetString() );
1278 }
1279 break;
1280 case HtmlOptionId::ALT:
1281 {
1282 if (!mxActEntry->bHasGraphic)
1283 { // ALT text only if not any image loaded
1284 if (!mxActEntry->aAltText.isEmpty())
1285 mxActEntry->aAltText += "; ";
1286
1287 mxActEntry->aAltText += rOption.GetString();
1288 }
1289 }
1290 break;
1291 case HtmlOptionId::WIDTH:
1292 {
1293 pImage->aSize.setWidth( static_cast<tools::Long>(rOption.GetNumber()) );
1294 }
1295 break;
1296 case HtmlOptionId::HEIGHT:
1297 {
1298 pImage->aSize.setHeight( static_cast<tools::Long>(rOption.GetNumber()) );
1299 }
1300 break;
1301 case HtmlOptionId::HSPACE:
1302 {
1303 pImage->aSpace.setX( static_cast<tools::Long>(rOption.GetNumber()) );
1304 }
1305 break;
1306 case HtmlOptionId::VSPACE:
1307 {
1308 pImage->aSpace.setY( static_cast<tools::Long>(rOption.GetNumber()) );
1309 }
1310 break;
1311 default: break;
1312 }
1313 }
1314 if (pImage->aURL.isEmpty())
1315 {
1316 OSL_FAIL( "Image: graphic without URL ?!?" );
1317 return ;
1318 }
1319
1320 sal_uInt16 nFormat;
1321 std::optional<Graphic> oGraphic(std::in_place);
1323 if ( ERRCODE_NONE != GraphicFilter::LoadGraphic( pImage->aURL, pImage->aFilterName,
1324 *oGraphic, &rFilter, &nFormat ) )
1325 {
1326 return ; // Bad luck
1327 }
1328 if (!mxActEntry->bHasGraphic)
1329 { // discard any ALT text in this cell if we have any image
1330 mxActEntry->bHasGraphic = true;
1331 mxActEntry->aAltText.clear();
1332 }
1333 pImage->aFilterName = rFilter.GetImportFormatName( nFormat );
1334 pImage->oGraphic = std::move( oGraphic );
1335 if ( !(pImage->aSize.Width() && pImage->aSize.Height()) )
1336 {
1338 pImage->aSize = pDefaultDev->LogicToPixel( pImage->oGraphic->GetPrefSize(),
1339 pImage->oGraphic->GetPrefMapMode() );
1340 }
1341 if (mxActEntry->maImageList.empty())
1342 return;
1343
1344 tools::Long nWidth = 0;
1345 for (const std::unique_ptr<ScHTMLImage> & pI : mxActEntry->maImageList)
1346 {
1347 if ( pI->nDir & nHorizontal )
1348 nWidth += pI->aSize.Width() + 2 * pI->aSpace.X();
1349 else
1350 nWidth = 0;
1351 }
1352 if ( mxActEntry->nWidth
1353 && (nWidth + pImage->aSize.Width() + 2 * pImage->aSpace.X()
1354 >= mxActEntry->nWidth) )
1355 mxActEntry->maImageList.back()->nDir = nVertical;
1356}
1357
1359{
1360 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1361 for (const auto & rOption : rOptions)
1362 {
1363 if( rOption.GetToken() == HtmlOptionId::WIDTH )
1364 {
1365 sal_uInt16 nVal = GetWidthPixel( rOption );
1366 MakeCol( pLocalColOffset, nColOffset, nVal, 0, 0 );
1367 nColOffset = nColOffset + nVal;
1368 }
1369 }
1370}
1371
1373{
1374 const OUString& rOptVal = rOption.GetString();
1375 if ( rOptVal.indexOf('%') != -1 )
1376 { // Percent
1377 sal_uInt16 nW = (nTableWidth ? nTableWidth : static_cast<sal_uInt16>(aPageSize.Width()));
1378 return static_cast<sal_uInt16>((rOption.GetNumber() * nW) / 100);
1379 }
1380 else
1381 {
1382 if ( rOptVal.indexOf('*') != -1 )
1383 { // Relative to what?
1384 // TODO: Collect all relative values in ColArray and then MakeCol
1385 return 0;
1386 }
1387 else
1388 return static_cast<sal_uInt16>(rOption.GetNumber()); // Pixel
1389 }
1390}
1391
1393{
1394 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1395 for (const auto & rOption : rOptions)
1396 {
1397 if( rOption.GetToken() == HtmlOptionId::NAME )
1398 mxActEntry->pName = rOption.GetString();
1399 }
1400}
1401
1403{
1404 ESelection& rSel = mxActEntry->aSel;
1405 return rSel.nStartPara == rSel.nEndPara &&
1406 rSel.nStartPara <= pInfo->aSelection.nEndPara &&
1407 pEdit->GetTextLen( rSel.nStartPara ) == 0;
1408}
1409
1411{
1412 if ( !IsAtBeginningOfText( pInfo ) )
1413 return;
1414
1415// Only at the start of the text; applies to whole line
1416 const HTMLOptions& rOptions = static_cast<HTMLParser*>(pInfo->pParser)->GetOptions();
1417 for (const auto & rOption : rOptions)
1418 {
1419 switch( rOption.GetToken() )
1420 {
1421 case HtmlOptionId::FACE :
1422 {
1423 const OUString& rFace = rOption.GetString();
1424 OUStringBuffer aFontName;
1425 sal_Int32 nPos = 0;
1426 while( nPos != -1 )
1427 {
1428 // Font list, VCL uses the semicolon as separator
1429 // HTML uses the comma
1430 std::u16string_view aFName = o3tl::getToken(rFace, 0, ',', nPos );
1431 aFName = comphelper::string::strip(aFName, ' ');
1432 if( !aFontName.isEmpty() )
1433 aFontName.append(";");
1434 aFontName.append(aFName);
1435 }
1436 if ( !aFontName.isEmpty() )
1437 mxActEntry->aItemSet.Put( SvxFontItem( FAMILY_DONTKNOW,
1438 aFontName.makeStringAndClear(), OUString(), PITCH_DONTKNOW,
1439 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
1440 }
1441 break;
1442 case HtmlOptionId::SIZE :
1443 {
1444 sal_uInt16 nSize = static_cast<sal_uInt16>(rOption.GetNumber());
1445 if ( nSize == 0 )
1446 nSize = 1;
1447 else if ( nSize > SC_HTML_FONTSIZES )
1448 nSize = SC_HTML_FONTSIZES;
1449 mxActEntry->aItemSet.Put( SvxFontHeightItem(
1450 maFontHeights[nSize-1], 100, ATTR_FONT_HEIGHT ) );
1451 }
1452 break;
1453 case HtmlOptionId::COLOR :
1454 {
1455 Color aColor;
1456 rOption.GetColor( aColor );
1457 mxActEntry->aItemSet.Put( SvxColorItem( aColor, ATTR_FONT_COLOR ) );
1458 }
1459 break;
1460 default: break;
1461 }
1462 }
1463}
1464
1466{
1467 switch ( pInfo->nToken )
1468 {
1469 case HtmlTokenId::META:
1470 {
1471 HTMLParser* pParser = static_cast<HTMLParser*>(pInfo->pParser);
1472 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1473 mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
1474 pParser->ParseMetaOptions(
1475 xDPS->getDocumentProperties(),
1477 }
1478 break;
1479 case HtmlTokenId::TITLE_ON:
1480 {
1481 bInTitle = true;
1482 aString.clear();
1483 }
1484 break;
1485 case HtmlTokenId::TITLE_OFF:
1486 {
1487 if ( bInTitle && !aString.isEmpty() )
1488 {
1489 // Remove blanks from line breaks
1490 aString = aString.trim();
1491 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
1493 uno::UNO_QUERY_THROW);
1494 xDPS->getDocumentProperties()->setTitle(aString);
1495 }
1496 bInTitle = false;
1497 }
1498 break;
1499 case HtmlTokenId::TABLE_ON:
1500 {
1501 TableOn( pInfo );
1502 }
1503 break;
1504 case HtmlTokenId::COL_ON:
1505 {
1506 ColOn( pInfo );
1507 }
1508 break;
1509 case HtmlTokenId::TABLEHEADER_ON: // Opens row
1510 {
1511 if ( bInCell )
1512 CloseEntry( pInfo );
1513 // Do not set bInCell to true, TableDataOn does that
1514 mxActEntry->aItemSet.Put(
1516 [[fallthrough]];
1517 }
1518 case HtmlTokenId::TABLEDATA_ON: // Opens cell
1519 {
1520 TableDataOn( pInfo );
1521 }
1522 break;
1523 case HtmlTokenId::TABLEHEADER_OFF:
1524 case HtmlTokenId::TABLEDATA_OFF: // Closes cell
1525 {
1526 TableDataOff( pInfo );
1527 }
1528 break;
1529 case HtmlTokenId::TABLEROW_ON: // Before first cell in row
1530 {
1531 TableRowOn( pInfo );
1532 }
1533 break;
1534 case HtmlTokenId::TABLEROW_OFF: // After last cell in row
1535 {
1536 TableRowOff( pInfo );
1537 }
1538 break;
1539 case HtmlTokenId::TABLE_OFF:
1540 {
1541 TableOff( pInfo );
1542 }
1543 break;
1544 case HtmlTokenId::IMAGE:
1545 {
1546 Image( pInfo );
1547 }
1548 break;
1549 case HtmlTokenId::PARABREAK_OFF:
1550 { // We continue vertically after an image
1551 if (!mxActEntry->maImageList.empty())
1552 mxActEntry->maImageList.back()->nDir = nVertical;
1553 }
1554 break;
1555 case HtmlTokenId::ANCHOR_ON:
1556 {
1557 AnchorOn( pInfo );
1558 }
1559 break;
1560 case HtmlTokenId::FONT_ON :
1561 {
1562 FontOn( pInfo );
1563 }
1564 break;
1565 case HtmlTokenId::BIGPRINT_ON :
1566 {
1567 // TODO: Remember current font size and increase by 1
1568 if ( IsAtBeginningOfText( pInfo ) )
1569 mxActEntry->aItemSet.Put( SvxFontHeightItem(
1570 maFontHeights[3], 100, ATTR_FONT_HEIGHT ) );
1571 }
1572 break;
1573 case HtmlTokenId::SMALLPRINT_ON :
1574 {
1575 // TODO: Remember current font size and decrease by 1
1576 if ( IsAtBeginningOfText( pInfo ) )
1577 mxActEntry->aItemSet.Put( SvxFontHeightItem(
1578 maFontHeights[0], 100, ATTR_FONT_HEIGHT ) );
1579 }
1580 break;
1581 case HtmlTokenId::BOLD_ON :
1582 case HtmlTokenId::STRONG_ON :
1583 {
1584 if ( IsAtBeginningOfText( pInfo ) )
1585 mxActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
1586 ATTR_FONT_WEIGHT ) );
1587 }
1588 break;
1589 case HtmlTokenId::ITALIC_ON :
1590 case HtmlTokenId::EMPHASIS_ON :
1591 case HtmlTokenId::ADDRESS_ON :
1592 case HtmlTokenId::BLOCKQUOTE_ON :
1593 case HtmlTokenId::BLOCKQUOTE30_ON :
1594 case HtmlTokenId::CITATION_ON :
1595 case HtmlTokenId::VARIABLE_ON :
1596 {
1597 if ( IsAtBeginningOfText( pInfo ) )
1598 mxActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
1600 }
1601 break;
1602 case HtmlTokenId::DEFINSTANCE_ON :
1603 {
1604 if ( IsAtBeginningOfText( pInfo ) )
1605 {
1606 mxActEntry->aItemSet.Put( SvxWeightItem( WEIGHT_BOLD,
1607 ATTR_FONT_WEIGHT ) );
1608 mxActEntry->aItemSet.Put( SvxPostureItem( ITALIC_NORMAL,
1610 }
1611 }
1612 break;
1613 case HtmlTokenId::UNDERLINE_ON :
1614 {
1615 if ( IsAtBeginningOfText( pInfo ) )
1618 }
1619 break;
1620 case HtmlTokenId::TEXTTOKEN:
1621 {
1622 if ( bInTitle )
1623 aString += pInfo->aText;
1624 }
1625 break;
1626 default: ;
1627 }
1628}
1629
1630// HTML DATA QUERY PARSER
1631
1632template< typename Type >
1633static Type getLimitedValue( const Type& rValue, const Type& rMin, const Type& rMax )
1634{ return std::clamp( rValue, rMin, rMax ); }
1635
1637 ScEEParseEntry( rItemSet ),
1638 mbImportAlways( false )
1639{
1640 nTab = nTableId;
1641 bEntirePara = false;
1642}
1643
1645{
1646 return mbImportAlways || aSel.HasRange() || !aAltText.isEmpty() || IsTable();
1647}
1648
1650{
1651 // set start position
1654 // adjust end position
1656 {
1659 }
1660}
1661
1663{
1664 OSL_ENSURE( (aSel.nEndPara < rInfo.aSelection.nEndPara) ||
1665 ((aSel.nEndPara == rInfo.aSelection.nEndPara) && (aSel.nEndPos <= rInfo.aSelection.nEndPos)),
1666 "ScHTMLQueryParser::AdjustEntryEnd - invalid end position" );
1667 // set end position
1670}
1671
1672void ScHTMLEntry::Strip( const EditEngine& rEditEngine )
1673{
1674 // strip leading empty paragraphs
1675 while( (aSel.nStartPara < aSel.nEndPara) && (rEditEngine.GetTextLen( aSel.nStartPara ) <= aSel.nStartPos) )
1676 {
1677 ++aSel.nStartPara;
1678 aSel.nStartPos = 0;
1679 }
1680 // strip trailing empty paragraphs
1681 while( (aSel.nStartPara < aSel.nEndPara) && (aSel.nEndPos == 0) )
1682 {
1683 --aSel.nEndPara;
1684 aSel.nEndPos = rEditEngine.GetTextLen( aSel.nEndPara );
1685 }
1686}
1687
1696{
1697private:
1698 typedef std::shared_ptr< ScHTMLTable > ScHTMLTablePtr;
1699 typedef std::map< ScHTMLTableId, ScHTMLTablePtr > ScHTMLTableStdMap;
1700
1701public:
1702 typedef ScHTMLTableStdMap::iterator iterator;
1703 typedef ScHTMLTableStdMap::const_iterator const_iterator;
1704
1705private:
1709
1710public:
1711 explicit ScHTMLTableMap( ScHTMLTable& rParentTable );
1712
1713 const_iterator begin() const { return maTables.begin(); }
1714 const_iterator end() const { return maTables.end(); }
1715
1719 ScHTMLTable* FindTable( ScHTMLTableId nTableId, bool bDeep = true ) const;
1720
1723 ScHTMLTable* CreateTable( const HtmlImportInfo& rInfo, bool bPreFormText, const ScDocument& rDoc );
1724
1725private:
1727 void SetCurrTable( ScHTMLTable* pTable ) const
1728 { if( pTable ) mpCurrTable = pTable; }
1729};
1730
1732 mrParentTable(rParentTable),
1733 mpCurrTable(nullptr)
1734{
1735}
1736
1738{
1739 ScHTMLTable* pResult = nullptr;
1740 if( mpCurrTable && (nTableId == mpCurrTable->GetTableId()) )
1741 pResult = mpCurrTable; // cached table
1742 else
1743 {
1744 const_iterator aFind = maTables.find( nTableId );
1745 if( aFind != maTables.end() )
1746 pResult = aFind->second.get(); // table from this container
1747 }
1748
1749 // not found -> search deep in nested tables
1750 if( !pResult && bDeep )
1751 for( const_iterator aIter = begin(), aEnd = end(); !pResult && (aIter != aEnd); ++aIter )
1752 pResult = aIter->second->FindNestedTable( nTableId );
1753
1754 SetCurrTable( pResult );
1755 return pResult;
1756}
1757
1758ScHTMLTable* ScHTMLTableMap::CreateTable( const HtmlImportInfo& rInfo, bool bPreFormText, const ScDocument& rDoc )
1759{
1760 ScHTMLTable* pTable = new ScHTMLTable( mrParentTable, rInfo, bPreFormText, rDoc );
1761 maTables[ pTable->GetTableId() ].reset( pTable );
1762 SetCurrTable( pTable );
1763 return pTable;
1764}
1765
1766namespace {
1767
1774class ScHTMLTableIterator
1775{
1776public:
1779 explicit ScHTMLTableIterator( const ScHTMLTableMap* pTableMap );
1780
1781 bool is() const { return mpTableMap && maIter != maEnd; }
1782 ScHTMLTable* operator->() { return maIter->second.get(); }
1783 ScHTMLTableIterator& operator++() { ++maIter; return *this; }
1784
1785private:
1788 const ScHTMLTableMap* mpTableMap;
1789};
1790
1791}
1792
1793ScHTMLTableIterator::ScHTMLTableIterator( const ScHTMLTableMap* pTableMap ) :
1794 mpTableMap(pTableMap)
1795{
1796 if( pTableMap )
1797 {
1798 maIter = pTableMap->begin();
1799 maEnd = pTableMap->end();
1800 }
1801}
1802
1804 mnTableId( rnUnusedId ),
1805 mrnUnusedId( rnUnusedId )
1806{
1807 ++mrnUnusedId;
1808}
1809
1810ScHTMLTable::ScHTMLTable( ScHTMLTable& rParentTable, const HtmlImportInfo& rInfo, bool bPreFormText, const ScDocument& rDoc ) :
1811 mpParentTable( &rParentTable ),
1812 maTableId( rParentTable.maTableId.mrnUnusedId ),
1813 maTableItemSet( rParentTable.GetCurrItemSet() ),
1814 mrEditEngine( rParentTable.mrEditEngine ),
1815 mrEEParseList( rParentTable.mrEEParseList ),
1816 mpCurrEntryVector( nullptr ),
1817 maSize( 1, 1 ),
1818 mpParser(rParentTable.mpParser),
1819 mrDoc(rDoc),
1820 mbBorderOn( false ),
1821 mbPreFormText( bPreFormText ),
1822 mbRowOn( false ),
1823 mbDataOn( false ),
1824 mbPushEmptyLine( false ),
1825 mbCaptionOn ( false )
1826{
1827 if( mbPreFormText )
1828 {
1829 ImplRowOn();
1830 ImplDataOn( ScHTMLSize( 1, 1 ) );
1831 }
1832 else
1833 {
1835 const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
1836 for (const auto& rOption : rOptions)
1837 {
1838 switch( rOption.GetToken() )
1839 {
1840 case HtmlOptionId::BORDER:
1841 mbBorderOn = rOption.GetString().isEmpty() || (rOption.GetNumber() != 0);
1842 break;
1843 case HtmlOptionId::ID:
1844 maTableName = rOption.GetString();
1845 break;
1846 default: break;
1847 }
1848 }
1849 }
1850
1851 CreateNewEntry( rInfo );
1852}
1853
1855 SfxItemPool& rPool,
1856 EditEngine& rEditEngine,
1857 std::vector<std::shared_ptr<ScEEParseEntry>>& rEEParseList,
1858 ScHTMLTableId& rnUnusedId, ScHTMLParser* pParser, const ScDocument& rDoc
1859) :
1860 mpParentTable( nullptr ),
1861 maTableId( rnUnusedId ),
1862 maTableItemSet( rPool ),
1863 mrEditEngine( rEditEngine ),
1864 mrEEParseList( rEEParseList ),
1865 mpCurrEntryVector( nullptr ),
1866 maSize( 1, 1 ),
1867 mpParser(pParser),
1868 mrDoc(rDoc),
1869 mbBorderOn( false ),
1870 mbPreFormText( false ),
1871 mbRowOn( false ),
1872 mbDataOn( false ),
1873 mbPushEmptyLine( false ),
1874 mbCaptionOn ( false )
1875{
1876 // open the first "cell" of the document
1877 ImplRowOn();
1878 ImplDataOn( ScHTMLSize( 1, 1 ) );
1880}
1881
1883{
1884}
1885
1887{
1888 // first try cell item set, then row item set, then table item set
1890}
1891
1893{
1894 ScHTMLSize aSpan( 1, 1 );
1895 const ScRange* pRange = maVMergedCells.Find( rCellPos.MakeAddr() );
1896 if (!pRange)
1897 pRange = maHMergedCells.Find( rCellPos.MakeAddr() );
1898 if (pRange)
1899 aSpan.Set( pRange->aEnd.Col() - pRange->aStart.Col() + 1, pRange->aEnd.Row() - pRange->aStart.Row() + 1 );
1900 return aSpan;
1901}
1902
1904{
1905 return mxNestedTables ? mxNestedTables->FindTable( nTableId ) : nullptr;
1906}
1907
1909{
1910 OSL_ENSURE( mxCurrEntry, "ScHTMLTable::PutItem - no current entry" );
1911 if( mxCurrEntry && mxCurrEntry->IsEmpty() )
1912 mxCurrEntry->GetItemSet().Put( rItem );
1913}
1914
1916{
1917 OSL_ENSURE( mxCurrEntry, "ScHTMLTable::PutText - no current entry" );
1918 if( mxCurrEntry )
1919 {
1920 if( !mxCurrEntry->HasContents() && IsSpaceCharInfo( rInfo ) )
1921 mxCurrEntry->AdjustStart( rInfo );
1922 else
1923 mxCurrEntry->AdjustEnd( rInfo );
1924 if (mbCaptionOn)
1925 maCaptionBuffer.append(rInfo.aText);
1926
1927 }
1928}
1929
1931{
1932 if( mxCurrEntry && mbDataOn && !IsEmptyCell() )
1933 mxCurrEntry->SetImportAlways();
1934 PushEntry( rInfo );
1935 CreateNewEntry( rInfo );
1937}
1938
1940{
1941 // empty line, if <br> is at start of cell
1943}
1944
1946{
1947 // call directly, InsertPara() has not been called before
1949}
1950
1952{
1953 // empty line, if <p>, </p>, <h?>, or </h*> are not at start of cell
1955}
1956
1958{
1959 OSL_ENSURE( mxCurrEntry, "ScHTMLTable::AnchorOn - no current entry" );
1960 // don't skip entries with single hyperlinks
1961 if( mxCurrEntry )
1962 mxCurrEntry->SetImportAlways();
1963}
1964
1966{
1967 PushEntry( rInfo );
1968 return InsertNestedTable( rInfo, false );
1969}
1970
1972{
1973 return mbPreFormText ? this : CloseTable( rInfo );
1974}
1975
1977{
1978 mbCaptionOn = true;
1979 maCaptionBuffer.setLength(0);
1980}
1981
1983{
1984 if (!mbCaptionOn)
1985 return;
1986 maCaption = maCaptionBuffer.makeStringAndClear().trim();
1987 mbCaptionOn = false;
1988}
1989
1991{
1992 PushEntry( rInfo );
1993 return InsertNestedTable( rInfo, true );
1994}
1995
1997{
1998 return mbPreFormText ? CloseTable( rInfo ) : this;
1999}
2000
2002{
2003 PushEntry( rInfo, true );
2004 if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
2005 {
2006 ImplRowOn();
2008 }
2009 CreateNewEntry( rInfo );
2010}
2011
2013{
2014 PushEntry( rInfo, true );
2015 if( mpParentTable && !mbPreFormText ) // no rows allowed in global and preformatted tables
2016 ImplRowOff();
2017 CreateNewEntry( rInfo );
2018}
2019
2020namespace {
2021
2026OUString decodeNumberFormat(const OUString& rFmt)
2027{
2028 OUStringBuffer aBuf;
2029 const sal_Unicode* p = rFmt.getStr();
2030 sal_Int32 n = rFmt.getLength();
2031 for (sal_Int32 i = 0; i < n; ++i, ++p)
2032 {
2033 if (*p == '\\')
2034 {
2035 // Skip '\'.
2036 ++i;
2037 ++p;
2038
2039 // Parse all subsequent digits until first non-digit is found.
2040 sal_Int32 nDigitCount = 0;
2041 const sal_Unicode* p1 = p;
2042 for (; i < n; ++i, ++p, ++nDigitCount)
2043 {
2044 if (*p < '0' || '9' < *p)
2045 {
2046 --i;
2047 --p;
2048 break;
2049 }
2050
2051 }
2052 if (nDigitCount)
2053 {
2054 // Hex-encoded character found. Decode it back into its
2055 // original character. An example of number format with
2056 // hex-encoded chars: "\0022$\0022\#\,\#\#0\.00"
2057 sal_uInt32 nVal = OUString(p1, nDigitCount).toUInt32(16);
2058 aBuf.append(static_cast<sal_Unicode>(nVal));
2059 }
2060 }
2061 else
2062 aBuf.append(*p);
2063 }
2064 return aBuf.makeStringAndClear();
2065}
2066
2067}
2068
2070{
2071 PushEntry( rInfo, true );
2072 if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
2073 {
2074 // read needed options from the <td> tag
2075 ScHTMLSize aSpanSize( 1, 1 );
2076 std::optional<OUString> pValStr, pNumStr;
2077 const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
2078 sal_uInt32 nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
2079 for (const auto& rOption : rOptions)
2080 {
2081 switch (rOption.GetToken())
2082 {
2083 case HtmlOptionId::COLSPAN:
2084 aSpanSize.mnCols = static_cast<SCCOL>( getLimitedValue<sal_Int32>( rOption.GetString().toInt32(), 1, 256 ) );
2085 break;
2086 case HtmlOptionId::ROWSPAN:
2087 aSpanSize.mnRows = static_cast<SCROW>( getLimitedValue<sal_Int32>( rOption.GetString().toInt32(), 1, 256 ) );
2088 break;
2089 case HtmlOptionId::SDVAL:
2090 pValStr = rOption.GetString();
2091 break;
2092 case HtmlOptionId::SDNUM:
2093 pNumStr = rOption.GetString();
2094 break;
2095 case HtmlOptionId::CLASS:
2096 {
2097 // Pick up the number format associated with this class (if
2098 // any).
2099 OUString aClass = rOption.GetString();
2100 const ScHTMLStyles& rStyles = mpParser->GetStyles();
2101 const OUString& rVal = rStyles.getPropertyValue("td", aClass, "mso-number-format");
2102 if (!rVal.isEmpty())
2103 {
2104 OUString aNumFmt = decodeNumberFormat(rVal);
2105
2106 nNumberFormat = GetFormatTable()->GetEntryKey(aNumFmt);
2107 if (nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
2108 {
2109 sal_Int32 nErrPos = 0;
2110 SvNumFormatType nDummy;
2111 bool bValidFmt = GetFormatTable()->PutEntry(aNumFmt, nErrPos, nDummy, nNumberFormat);
2112 if (!bValidFmt)
2113 nNumberFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
2114 }
2115 }
2116 }
2117 break;
2118 default: break;
2119 }
2120 }
2121
2122 ImplDataOn( aSpanSize );
2123
2124 if (nNumberFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
2125 moDataItemSet->Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat) );
2126
2128 CreateNewEntry( rInfo );
2129 mxCurrEntry->pValStr = std::move(pValStr);
2130 mxCurrEntry->pNumStr = std::move(pNumStr);
2131 }
2132 else
2133 CreateNewEntry( rInfo );
2134}
2135
2137{
2138 PushEntry( rInfo, true );
2139 if( mpParentTable && !mbPreFormText ) // no cells allowed in global and preformatted tables
2140 ImplDataOff();
2141 CreateNewEntry( rInfo );
2142}
2143
2145{
2146 bool bPushed = PushEntry( rInfo );
2147 if( !mpParentTable )
2148 {
2149 // do not start new row, if nothing (no title) precedes the body.
2150 if( bPushed || !mbRowOn )
2151 ImplRowOn();
2152 if( bPushed || !mbDataOn )
2153 ImplDataOn( ScHTMLSize( 1, 1 ) );
2155 }
2156 CreateNewEntry( rInfo );
2157}
2158
2160{
2161 PushEntry( rInfo );
2162 if( !mpParentTable )
2163 {
2164 ImplDataOff();
2165 ImplRowOff();
2166 }
2167 CreateNewEntry( rInfo );
2168}
2169
2171{
2172 if( mpParentTable ) // not allowed to close global table
2173 {
2174 PushEntry( rInfo, mbDataOn );
2175 ImplDataOff();
2176 ImplRowOff();
2178 mpParentTable->CreateNewEntry( rInfo );
2179 if( mbPreFormText ) // enclose preformatted table with empty lines in parent table
2181 return mpParentTable;
2182 }
2183 return this;
2184}
2185
2187{
2188 const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2189 size_t nIndex = static_cast< size_t >( nCellPos );
2190 if( nIndex >= rSizes.size() ) return 0;
2191 return (nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]);
2192}
2193
2194SCCOLROW ScHTMLTable::GetDocSize( ScHTMLOrient eOrient, SCCOLROW nCellBegin, SCCOLROW nCellEnd ) const
2195{
2196 const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2197 size_t nBeginIdx = static_cast< size_t >( std::max< SCCOLROW >( nCellBegin, 0 ) );
2198 size_t nEndIdx = static_cast< size_t >( std::min< SCCOLROW >( nCellEnd, static_cast< SCCOLROW >( rSizes.size() ) ) );
2199 if (nBeginIdx >= nEndIdx ) return 0;
2200 return rSizes[ nEndIdx - 1 ] - ((nBeginIdx == 0) ? 0 : rSizes[ nBeginIdx - 1 ]);
2201}
2202
2204{
2205 const ScSizeVec& rSizes = maCumSizes[ eOrient ];
2206 return rSizes.empty() ? 0 : rSizes.back();
2207}
2208
2210{
2211 ScHTMLSize aCellSpan = GetSpan( rCellPos );
2212 return ScHTMLSize(
2213 static_cast< SCCOL >( GetDocSize( tdCol, rCellPos.mnCol, rCellPos.mnCol + aCellSpan.mnCols ) ),
2214 static_cast< SCROW >( GetDocSize( tdRow, rCellPos.mnRow, rCellPos.mnRow + aCellSpan.mnRows ) ) );
2215}
2216
2218{
2219 return maDocBasePos.Get( eOrient ) + GetDocSize( eOrient, 0, nCellPos );
2220}
2221
2223{
2224 return ScHTMLPos(
2225 static_cast< SCCOL >( GetDocPos( tdCol, rCellPos.mnCol ) ),
2226 static_cast< SCROW >( GetDocPos( tdRow, rCellPos.mnRow ) ) );
2227}
2228
2230{
2231 rRange.aStart = rRange.aEnd = maDocBasePos.MakeAddr();
2233 if (!rRange.aEnd.Move( static_cast< SCCOL >( GetDocSize( tdCol ) ) - 1,
2234 static_cast< SCROW >( GetDocSize( tdRow ) ) - 1, 0, aErrorPos, mrDoc ))
2235 {
2236 assert(!"can't move");
2237 }
2238}
2239
2240void ScHTMLTable::ApplyCellBorders( ScDocument* pDoc, const ScAddress& rFirstPos ) const
2241{
2242 OSL_ENSURE( pDoc, "ScHTMLTable::ApplyCellBorders - no document" );
2243 if( pDoc && mbBorderOn )
2244 {
2245 const SCCOL nLastCol = maSize.mnCols - 1;
2246 const SCROW nLastRow = maSize.mnRows - 1;
2247 const tools::Long nOuterLine = SvxBorderLineWidth::Medium;
2248 const tools::Long nInnerLine = SvxBorderLineWidth::Hairline;
2249 SvxBorderLine aOuterLine(nullptr, nOuterLine, SvxBorderLineStyle::SOLID);
2250 SvxBorderLine aInnerLine(nullptr, nInnerLine, SvxBorderLineStyle::SOLID);
2251 SvxBoxItem aBorderItem( ATTR_BORDER );
2252
2253 for( SCCOL nCol = 0; nCol <= nLastCol; ++nCol )
2254 {
2255 SvxBorderLine* pLeftLine = (nCol == 0) ? &aOuterLine : &aInnerLine;
2256 SvxBorderLine* pRightLine = (nCol == nLastCol) ? &aOuterLine : &aInnerLine;
2257 SCCOL nCellCol1 = static_cast< SCCOL >( GetDocPos( tdCol, nCol ) ) + rFirstPos.Col();
2258 SCCOL nCellCol2 = nCellCol1 + static_cast< SCCOL >( GetDocSize( tdCol, nCol ) ) - 1;
2259 for( SCROW nRow = 0; nRow <= nLastRow; ++nRow )
2260 {
2261 SvxBorderLine* pTopLine = (nRow == 0) ? &aOuterLine : &aInnerLine;
2262 SvxBorderLine* pBottomLine = (nRow == nLastRow) ? &aOuterLine : &aInnerLine;
2263 SCROW nCellRow1 = GetDocPos( tdRow, nRow ) + rFirstPos.Row();
2264 SCROW nCellRow2 = nCellRow1 + GetDocSize( tdRow, nRow ) - 1;
2265 for( SCCOL nCellCol = nCellCol1; nCellCol <= nCellCol2; ++nCellCol )
2266 {
2267 aBorderItem.SetLine( (nCellCol == nCellCol1) ? pLeftLine : nullptr, SvxBoxItemLine::LEFT );
2268 aBorderItem.SetLine( (nCellCol == nCellCol2) ? pRightLine : nullptr, SvxBoxItemLine::RIGHT );
2269 for( SCROW nCellRow = nCellRow1; nCellRow <= nCellRow2; ++nCellRow )
2270 {
2271 aBorderItem.SetLine( (nCellRow == nCellRow1) ? pTopLine : nullptr, SvxBoxItemLine::TOP );
2272 aBorderItem.SetLine( (nCellRow == nCellRow2) ? pBottomLine : nullptr, SvxBoxItemLine::BOTTOM );
2273 pDoc->ApplyAttr( nCellCol, nCellRow, rFirstPos.Tab(), aBorderItem );
2274 }
2275 }
2276 }
2277 }
2278 }
2279
2280 for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2281 aIter->ApplyCellBorders( pDoc, rFirstPos );
2282}
2283
2285{
2286 return mpParser->GetDoc().GetFormatTable();
2287}
2288
2290{
2291 return mpCurrEntryVector && mpCurrEntryVector->empty();
2292}
2293
2295{
2296 return (rInfo.nToken == HtmlTokenId::TEXTTOKEN) && (rInfo.aText.getLength() == 1) && (rInfo.aText[ 0 ] == ' ');
2297}
2298
2300{
2301 return std::make_unique<ScHTMLEntry>( GetCurrItemSet() );
2302}
2303
2305{
2306 OSL_ENSURE( !mxCurrEntry, "ScHTMLTable::CreateNewEntry - old entry still present" );
2308 mxCurrEntry->aSel = rInfo.aSelection;
2309}
2310
2312{
2313 // HTML entry list does not own the entries
2314 rEntryVector.push_back( rxEntry.get() );
2315 // mrEEParseList (reference to member of ScEEParser) owns the entries
2316 mrEEParseList.push_back(std::shared_ptr<ScEEParseEntry>(rxEntry.release()));
2317}
2318
2320{
2321 bool bPushed = false;
2322 if( rxEntry && rxEntry->HasContents() )
2323 {
2324 if( mpCurrEntryVector )
2325 {
2326 if( mbPushEmptyLine )
2327 {
2328 ScHTMLEntryPtr xEmptyEntry = CreateEntry();
2330 mbPushEmptyLine = false;
2331 }
2333 bPushed = true;
2334 }
2335 else if( mpParentTable )
2336 {
2337 bPushed = mpParentTable->PushEntry( rxEntry );
2338 }
2339 else
2340 {
2341 OSL_FAIL( "ScHTMLTable::PushEntry - cannot push entry, no parent found" );
2342 }
2343 }
2344 return bPushed;
2345}
2346
2347bool ScHTMLTable::PushEntry( const HtmlImportInfo& rInfo, bool bLastInCell )
2348{
2349 OSL_ENSURE( mxCurrEntry, "ScHTMLTable::PushEntry - no current entry" );
2350 bool bPushed = false;
2351 if( mxCurrEntry )
2352 {
2353 mxCurrEntry->AdjustEnd( rInfo );
2354 mxCurrEntry->Strip( mrEditEngine );
2355
2356 // import entry always, if it is the last in cell, and cell is still empty
2357 if( bLastInCell && IsEmptyCell() )
2358 {
2359 mxCurrEntry->SetImportAlways();
2360 // don't insert empty lines before single empty entries
2361 if( mxCurrEntry->IsEmpty() )
2362 mbPushEmptyLine = false;
2363 }
2364
2365 bPushed = PushEntry( mxCurrEntry );
2366 mxCurrEntry.reset();
2367 }
2368 return bPushed;
2369}
2370
2372{
2373 OSL_ENSURE( nTableId != SC_HTML_GLOBAL_TABLE, "ScHTMLTable::PushTableEntry - cannot push global table" );
2374 if( nTableId != SC_HTML_GLOBAL_TABLE )
2375 {
2376 ScHTMLEntryPtr xEntry( new ScHTMLEntry( maTableItemSet, nTableId ) );
2377 PushEntry( xEntry );
2378 }
2379}
2380
2382{
2383 ScHTMLTable* pTable = ((nTableId != SC_HTML_GLOBAL_TABLE) && mxNestedTables) ?
2384 mxNestedTables->FindTable( nTableId, false ) : nullptr;
2385 OSL_ENSURE( pTable || (nTableId == SC_HTML_GLOBAL_TABLE), "ScHTMLTable::GetExistingTable - table not found" );
2386 return pTable;
2387}
2388
2390{
2391 if( !mxNestedTables )
2392 mxNestedTables.reset( new ScHTMLTableMap( *this ) );
2393 if( bPreFormText ) // enclose new preformatted table with empty lines
2395 return mxNestedTables->CreateTable( rInfo, bPreFormText, mrDoc );
2396}
2397
2399{
2400 ScRange* pRange;
2401
2402 /* Find an unused cell by skipping all merged ranges that cover the
2403 current cell position stored in maCurrCell. */
2404 for (;;)
2405 {
2406 pRange = maVMergedCells.Find( maCurrCell.MakeAddr() );
2407 if (!pRange)
2408 pRange = maHMergedCells.Find( maCurrCell.MakeAddr() );
2409 if (!pRange)
2410 break;
2411 maCurrCell.mnCol = pRange->aEnd.Col() + 1;
2412 }
2414
2415 /* If the new cell is merged horizontally, try to find collisions with
2416 other vertically merged ranges. In this case, shrink existing
2417 vertically merged ranges (do not shrink the new cell). */
2418 SCCOL nColEnd = maCurrCell.mnCol + rSpanSize.mnCols;
2419 for( ScAddress aAddr( maCurrCell.MakeAddr() ); aAddr.Col() < nColEnd; aAddr.IncCol() )
2420 if( (pRange = maVMergedCells.Find( aAddr )) != nullptr )
2421 pRange->aEnd.SetRow( maCurrCell.mnRow - 1 );
2422
2423 // insert the new range into the cell lists
2424 ScRange aNewRange( maCurrCell.MakeAddr() );
2426 if (!aNewRange.aEnd.Move( rSpanSize.mnCols - 1, rSpanSize.mnRows - 1, 0, aErrorPos, mrDoc ))
2427 {
2428 assert(!"can't move");
2429 }
2430 if( rSpanSize.mnRows > 1 )
2431 {
2432 maVMergedCells.push_back( aNewRange );
2433 /* Do not insert vertically merged ranges into maUsedCells yet,
2434 because they may be shrunken (see above). The final vertically
2435 merged ranges are inserted in FillEmptyCells(). */
2436 }
2437 else
2438 {
2439 if( rSpanSize.mnCols > 1 )
2440 maHMergedCells.push_back( aNewRange );
2441 /* Insert horizontally merged ranges and single cells into
2442 maUsedCells, they will not be changed anymore. */
2443 maUsedCells.Join( aNewRange );
2444 }
2445
2446 // adjust table size
2447 maSize.mnCols = std::max< SCCOL >( maSize.mnCols, aNewRange.aEnd.Col() + 1 );
2448 maSize.mnRows = std::max< SCROW >( maSize.mnRows, aNewRange.aEnd.Row() + 1 );
2449}
2450
2452{
2453 if( mbRowOn )
2454 ImplRowOff();
2455 moRowItemSet.emplace( maTableItemSet );
2456 maCurrCell.mnCol = 0;
2457 mbRowOn = true;
2458 mbDataOn = false;
2459}
2460
2462{
2463 if( mbDataOn )
2464 ImplDataOff();
2465 if( mbRowOn )
2466 {
2467 moRowItemSet.reset();
2468 ++maCurrCell.mnRow;
2469 mbRowOn = mbDataOn = false;
2470 }
2471}
2472
2473void ScHTMLTable::ImplDataOn( const ScHTMLSize& rSpanSize )
2474{
2475 if( mbDataOn )
2476 ImplDataOff();
2477 if( !mbRowOn )
2478 ImplRowOn();
2479 moDataItemSet.emplace( *moRowItemSet );
2480 InsertNewCell( rSpanSize );
2481 mbDataOn = true;
2482 mbPushEmptyLine = false;
2483}
2484
2486{
2487 if( mbDataOn )
2488 {
2489 moDataItemSet.reset();
2490 ++maCurrCell.mnCol;
2491 mpCurrEntryVector = nullptr;
2492 mbDataOn = false;
2493 }
2494}
2495
2497{
2498 // special handling for table header cells
2499 if( rInfo.nToken == HtmlTokenId::TABLEHEADER_ON )
2500 {
2502 rItemSet.Put( SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY ) );
2503 }
2504
2505 const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
2506 for (const auto& rOption : rOptions)
2507 {
2508 switch( rOption.GetToken() )
2509 {
2510 case HtmlOptionId::ALIGN:
2511 {
2512 SvxCellHorJustify eVal = SvxCellHorJustify::Standard;
2513 const OUString& rOptVal = rOption.GetString();
2514 if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_right ) )
2515 eVal = SvxCellHorJustify::Right;
2516 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_center ) )
2517 eVal = SvxCellHorJustify::Center;
2518 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_AL_left ) )
2519 eVal = SvxCellHorJustify::Left;
2520 if( eVal != SvxCellHorJustify::Standard )
2521 rItemSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY ) );
2522 }
2523 break;
2524
2525 case HtmlOptionId::VALIGN:
2526 {
2527 SvxCellVerJustify eVal = SvxCellVerJustify::Standard;
2528 const OUString& rOptVal = rOption.GetString();
2529 if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_top ) )
2530 eVal = SvxCellVerJustify::Top;
2531 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_middle ) )
2532 eVal = SvxCellVerJustify::Center;
2533 else if( rOptVal.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_VA_bottom ) )
2534 eVal = SvxCellVerJustify::Bottom;
2535 if( eVal != SvxCellVerJustify::Standard )
2536 rItemSet.Put( SvxVerJustifyItem( eVal, ATTR_VER_JUSTIFY ) );
2537 }
2538 break;
2539
2540 case HtmlOptionId::BGCOLOR:
2541 {
2542 Color aColor;
2543 rOption.GetColor( aColor );
2544 rItemSet.Put( SvxBrushItem( aColor, ATTR_BACKGROUND ) );
2545 }
2546 break;
2547 default: break;
2548 }
2549 }
2550}
2551
2553{
2554 OSL_ENSURE( nCellPos >= 0, "ScHTMLTable::SetDocSize - unexpected negative position" );
2555 ScSizeVec& rSizes = maCumSizes[ eOrient ];
2556 size_t nIndex = static_cast< size_t >( nCellPos );
2557 // expand with height/width == 1
2558 while( nIndex >= rSizes.size() )
2559 rSizes.push_back( rSizes.empty() ? 1 : (rSizes.back() + 1) );
2560 // update size of passed position and all following
2561 // #i109987# only grow, don't shrink - use the largest needed size
2562 SCCOLROW nDiff = nSize - ((nIndex == 0) ? rSizes.front() : (rSizes[ nIndex ] - rSizes[ nIndex - 1 ]));
2563 if( nDiff > 0 )
2564 std::for_each(rSizes.begin() + nIndex, rSizes.end(), [&nDiff](SCCOLROW& rSize) { rSize += nDiff; });
2565}
2566
2568 ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nCellSpan, SCCOLROW nRealDocSize )
2569{
2570 SCCOLROW nDiffSize = 0;
2571 // in merged columns/rows: reduce needed size by size of leading columns
2572 while( nCellSpan > 1 )
2573 {
2574 nDiffSize += GetDocSize( eOrient, nCellPos );
2575 --nCellSpan;
2576 ++nCellPos;
2577 }
2578 // set remaining needed size to last column/row
2579 nRealDocSize -= std::min< SCCOLROW >( nRealDocSize - 1, nDiffSize );
2580 SetDocSize( eOrient, nCellPos, nRealDocSize );
2581}
2582
2584{
2585 for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2586 aIter->FillEmptyCells();
2587
2588 // insert the final vertically merged ranges into maUsedCells
2589 for ( size_t i = 0, nRanges = maVMergedCells.size(); i < nRanges; ++i )
2590 {
2591 ScRange & rRange = maVMergedCells[ i ];
2592 maUsedCells.Join( rRange );
2593 }
2594
2595 for( ScAddress aAddr; aAddr.Row() < maSize.mnRows; aAddr.IncRow() )
2596 {
2597 for( aAddr.SetCol( 0 ); aAddr.Col() < maSize.mnCols; aAddr.IncCol() )
2598 {
2599 if( !maUsedCells.Find( aAddr ) )
2600 {
2601 // create a range for the lock list (used to calc. cell span)
2602 ScRange aRange( aAddr );
2603 do
2604 {
2605 aRange.aEnd.IncCol();
2606 }
2607 while( (aRange.aEnd.Col() < maSize.mnCols) && !maUsedCells.Find( aRange.aEnd ) );
2608 aRange.aEnd.IncCol( -1 );
2609 maUsedCells.Join( aRange );
2610
2611 // insert a dummy entry
2612 ScHTMLEntryPtr xEntry = CreateEntry();
2613 ImplPushEntryToVector( maEntryMap[ ScHTMLPos( aAddr ) ], xEntry );
2614 }
2615 }
2616 }
2617}
2618
2620{
2621 // recalc table sizes recursively from inner to outer
2622 for( ScHTMLTableIterator aIter( mxNestedTables.get() ); aIter.is(); ++aIter )
2623 aIter->RecalcDocSize();
2624
2625 /* Two passes: first calculates the sizes of single columns/rows, then
2626 the sizes of spanned columns/rows. This allows to fill nested tables
2627 into merged cells optimally. */
2628 static const sal_uInt16 PASS_SINGLE = 0;
2629 static const sal_uInt16 PASS_SPANNED = 1;
2630 for( sal_uInt16 nPass = PASS_SINGLE; nPass <= PASS_SPANNED; ++nPass )
2631 {
2632 // iterate through every table cell
2633 for( const auto& [rCellPos, rEntryVector] : maEntryMap )
2634 {
2635 ScHTMLSize aCellSpan = GetSpan( rCellPos );
2636
2637 // process the dimension of the current cell in this pass?
2638 // (pass is single and span is 1) or (pass is not single and span is not 1)
2639 bool bProcessColWidth = ((nPass == PASS_SINGLE) == (aCellSpan.mnCols == 1));
2640 bool bProcessRowHeight = ((nPass == PASS_SINGLE) == (aCellSpan.mnRows == 1));
2641 if( bProcessColWidth || bProcessRowHeight )
2642 {
2643 ScHTMLSize aDocSize( 1, 0 ); // resulting size of the cell in document
2644
2645 // expand the cell size for each cell parse entry
2646 for( const auto& rpEntry : rEntryVector )
2647 {
2648 ScHTMLTable* pTable = GetExistingTable( rpEntry->GetTableId() );
2649 // find entry with maximum width
2650 if( bProcessColWidth && pTable )
2651 aDocSize.mnCols = std::max( aDocSize.mnCols, static_cast< SCCOL >( pTable->GetDocSize( tdCol ) ) );
2652 // add up height of each entry
2653 if( bProcessRowHeight )
2654 aDocSize.mnRows += pTable ? pTable->GetDocSize( tdRow ) : 1;
2655 }
2656 if( !aDocSize.mnRows )
2657 aDocSize.mnRows = 1;
2658
2659 if( bProcessColWidth )
2660 CalcNeededDocSize( tdCol, rCellPos.mnCol, aCellSpan.mnCols, aDocSize.mnCols );
2661 if( bProcessRowHeight )
2662 CalcNeededDocSize( tdRow, rCellPos.mnRow, aCellSpan.mnRows, aDocSize.mnRows );
2663 }
2664 }
2665 }
2666}
2667
2669{
2670 maDocBasePos = rBasePos;
2671 // after the previous assignment it is allowed to call GetDocPos() methods
2672
2673 // iterate through every table cell
2674 for( auto& [rCellPos, rEntryVector] : maEntryMap )
2675 {
2676 // fixed doc position of the entire cell (first entry)
2677 const ScHTMLPos aCellDocPos( GetDocPos( rCellPos ) );
2678 // fixed doc size of the entire cell
2679 const ScHTMLSize aCellDocSize( GetDocSize( rCellPos ) );
2680
2681 // running doc position for single entries
2682 ScHTMLPos aEntryDocPos( aCellDocPos );
2683
2684 ScHTMLEntry* pEntry = nullptr;
2685 for( const auto& rpEntry : rEntryVector )
2686 {
2687 pEntry = rpEntry;
2688 if( ScHTMLTable* pTable = GetExistingTable( pEntry->GetTableId() ) )
2689 {
2690 pTable->RecalcDocPos( aEntryDocPos ); // recalc nested table
2691 pEntry->nCol = SCCOL_MAX;
2692 pEntry->nRow = SCROW_MAX;
2693 SCROW nTableRows = static_cast< SCROW >( pTable->GetDocSize( tdRow ) );
2694
2695 // use this entry to pad empty space right of table
2696 if( mpParentTable ) // ... but not in global table
2697 {
2698 SCCOL nStartCol = aEntryDocPos.mnCol + static_cast< SCCOL >( pTable->GetDocSize( tdCol ) );
2699 SCCOL nNextCol = aEntryDocPos.mnCol + aCellDocSize.mnCols;
2700 if( nStartCol < nNextCol )
2701 {
2702 pEntry->nCol = nStartCol;
2703 pEntry->nRow = aEntryDocPos.mnRow;
2704 pEntry->nColOverlap = nNextCol - nStartCol;
2705 pEntry->nRowOverlap = nTableRows;
2706 }
2707 }
2708 aEntryDocPos.mnRow += nTableRows;
2709 }
2710 else
2711 {
2712 pEntry->nCol = aEntryDocPos.mnCol;
2713 pEntry->nRow = aEntryDocPos.mnRow;
2714 if( mpParentTable ) // do not merge in global table
2715 pEntry->nColOverlap = aCellDocSize.mnCols;
2716 ++aEntryDocPos.mnRow;
2717 }
2718 }
2719
2720 // pEntry points now to last entry.
2721 if( pEntry )
2722 {
2723 if( (pEntry == rEntryVector.front()) && (pEntry->GetTableId() == SC_HTML_NO_TABLE) )
2724 {
2725 // pEntry is the only entry in this cell - merge rows of cell with single non-table entry.
2726 pEntry->nRowOverlap = aCellDocSize.mnRows;
2727 }
2728 else
2729 {
2730 // fill up incomplete entry lists
2731 SCROW nFirstUnusedRow = aCellDocPos.mnRow + aCellDocSize.mnRows;
2732 while( aEntryDocPos.mnRow < nFirstUnusedRow )
2733 {
2734 ScHTMLEntryPtr xDummyEntry( new ScHTMLEntry( pEntry->GetItemSet() ) );
2735 xDummyEntry->nCol = aEntryDocPos.mnCol;
2736 xDummyEntry->nRow = aEntryDocPos.mnRow;
2737 xDummyEntry->nColOverlap = aCellDocSize.mnCols;
2738 ImplPushEntryToVector( rEntryVector, xDummyEntry );
2739 ++aEntryDocPos.mnRow;
2740 }
2741 }
2742 }
2743 }
2744}
2745
2747 SfxItemPool& rPool,
2748 EditEngine& rEditEngine,
2749 std::vector<std::shared_ptr<ScEEParseEntry>>& rEEParseVector,
2750 ScHTMLTableId& rnUnusedId,
2751 ScHTMLParser* pParser,
2752 const ScDocument& rDoc
2753) :
2754 ScHTMLTable( rPool, rEditEngine, rEEParseVector, rnUnusedId, pParser, rDoc )
2755{
2756}
2757
2759{
2760}
2761
2763{
2764 // Fills up empty cells with a dummy entry. */
2766 // recalc table sizes of all nested tables and this table
2767 RecalcDocSize();
2768 // recalc document positions of all entries in this table and in nested tables
2770}
2771
2773 ScHTMLParser( pEditEngine, pDoc ),
2774 mnUnusedId( SC_HTML_GLOBAL_TABLE ),
2775 mbTitleOn( false )
2776{
2777 mxGlobTable.reset(
2778 new ScHTMLGlobalTable(*pPool, *pEdit, maList, mnUnusedId, this, *pDoc));
2779 mpCurrTable = mxGlobTable.get();
2780}
2781
2783{
2784}
2785
2786ErrCode ScHTMLQueryParser::Read( SvStream& rStrm, const OUString& rBaseURL )
2787{
2788 SvKeyValueIteratorRef xValues;
2789 SvKeyValueIterator* pAttributes = nullptr;
2790
2792 if( pObjSh && pObjSh->IsLoading() )
2793 {
2794 pAttributes = pObjSh->GetHeaderAttributes();
2795 }
2796 else
2797 {
2798 /* When not loading, set up fake HTTP headers to force the SfxHTMLParser
2799 to use UTF8 (used when pasting from clipboard) */
2800 const char* pCharSet = rtl_getBestMimeCharsetFromTextEncoding( RTL_TEXTENCODING_UTF8 );
2801 if( pCharSet )
2802 {
2803 OUString aContentType = "text/html; charset=" +
2804 OUString::createFromAscii( pCharSet );
2805
2806 xValues = new SvKeyValueIterator;
2807 xValues->Append( SvKeyValue( OOO_STRING_SVTOOLS_HTML_META_content_type, aContentType ) );
2808 pAttributes = xValues.get();
2809 }
2810 }
2811
2813 pEdit->SetHtmlImportHdl( LINK( this, ScHTMLQueryParser, HTMLImportHdl ) );
2814 ErrCode nErr = pEdit->Read( rStrm, rBaseURL, EETextFormat::Html, pAttributes );
2815 pEdit->SetHtmlImportHdl( aOldLink );
2816
2817 mxGlobTable->Recalc();
2818 nColMax = static_cast< SCCOL >( mxGlobTable->GetDocSize( tdCol ) - 1 );
2819 nRowMax = static_cast< SCROW >( mxGlobTable->GetDocSize( tdRow ) - 1 );
2820
2821 return nErr;
2822}
2823
2825{
2826 return mxGlobTable.get();
2827}
2828
2830{
2831 switch( rInfo.nToken )
2832 {
2833// --- meta data ---
2834 case HtmlTokenId::META: MetaOn( rInfo ); break; // <meta>
2835
2836// --- title handling ---
2837 case HtmlTokenId::TITLE_ON: TitleOn(); break; // <title>
2838 case HtmlTokenId::TITLE_OFF: TitleOff( rInfo ); break; // </title>
2839
2840 case HtmlTokenId::STYLE_ON: break;
2841 case HtmlTokenId::STYLE_OFF: ParseStyle(rInfo.aText); break;
2842
2843// --- body handling ---
2844 case HtmlTokenId::BODY_ON: mpCurrTable->BodyOn( rInfo ); break; // <body>
2845 case HtmlTokenId::BODY_OFF: mpCurrTable->BodyOff( rInfo ); break; // </body>
2846
2847// --- insert text ---
2848 case HtmlTokenId::TEXTTOKEN: InsertText( rInfo ); break; // any text
2849 case HtmlTokenId::LINEBREAK: mpCurrTable->BreakOn(); break; // <br>
2850 case HtmlTokenId::HEAD1_ON: // <h1>
2851 case HtmlTokenId::HEAD2_ON: // <h2>
2852 case HtmlTokenId::HEAD3_ON: // <h3>
2853 case HtmlTokenId::HEAD4_ON: // <h4>
2854 case HtmlTokenId::HEAD5_ON: // <h5>
2855 case HtmlTokenId::HEAD6_ON: // <h6>
2856 case HtmlTokenId::PARABREAK_ON: mpCurrTable->HeadingOn(); break; // <p>
2857
2858// --- misc. contents ---
2859 case HtmlTokenId::ANCHOR_ON: mpCurrTable->AnchorOn(); break; // <a>
2860
2861// --- table handling ---
2862 case HtmlTokenId::TABLE_ON: TableOn( rInfo ); break; // <table>
2863 case HtmlTokenId::TABLE_OFF: TableOff( rInfo ); break; // </table>
2864 case HtmlTokenId::CAPTION_ON: mpCurrTable->CaptionOn(); break; // <caption>
2865 case HtmlTokenId::CAPTION_OFF: mpCurrTable->CaptionOff(); break; // </caption>
2866 case HtmlTokenId::TABLEROW_ON: mpCurrTable->RowOn( rInfo ); break; // <tr>
2867 case HtmlTokenId::TABLEROW_OFF: mpCurrTable->RowOff( rInfo ); break; // </tr>
2868 case HtmlTokenId::TABLEHEADER_ON: // <th>
2869 case HtmlTokenId::TABLEDATA_ON: mpCurrTable->DataOn( rInfo ); break; // <td>
2870 case HtmlTokenId::TABLEHEADER_OFF: // </th>
2871 case HtmlTokenId::TABLEDATA_OFF: mpCurrTable->DataOff( rInfo ); break; // </td>
2872 case HtmlTokenId::PREFORMTXT_ON: PreOn( rInfo ); break; // <pre>
2873 case HtmlTokenId::PREFORMTXT_OFF: PreOff( rInfo ); break; // </pre>
2874
2875// --- formatting ---
2876 case HtmlTokenId::FONT_ON: FontOn( rInfo ); break; // <font>
2877
2878 case HtmlTokenId::BIGPRINT_ON: // <big>
2881 break;
2882 case HtmlTokenId::SMALLPRINT_ON: // <small>
2885 break;
2886
2887 case HtmlTokenId::BOLD_ON: // <b>
2888 case HtmlTokenId::STRONG_ON: // <strong>
2890 break;
2891
2892 case HtmlTokenId::ITALIC_ON: // <i>
2893 case HtmlTokenId::EMPHASIS_ON: // <em>
2894 case HtmlTokenId::ADDRESS_ON: // <address>
2895 case HtmlTokenId::BLOCKQUOTE_ON: // <blockquote>
2896 case HtmlTokenId::BLOCKQUOTE30_ON: // <bq>
2897 case HtmlTokenId::CITATION_ON: // <cite>
2898 case HtmlTokenId::VARIABLE_ON: // <var>
2900 break;
2901
2902 case HtmlTokenId::DEFINSTANCE_ON: // <dfn>
2905 break;
2906
2907 case HtmlTokenId::UNDERLINE_ON: // <u>
2909 break;
2910 default: break;
2911 }
2912}
2913
2915{
2916 mpCurrTable->PutText( rInfo );
2917 if( mbTitleOn )
2918 maTitle.append(rInfo.aText);
2919}
2920
2922{
2923 const HTMLOptions& rOptions = static_cast<HTMLParser*>(rInfo.pParser)->GetOptions();
2924 for (const auto& rOption : rOptions)
2925 {
2926 switch( rOption.GetToken() )
2927 {
2928 case HtmlOptionId::FACE :
2929 {
2930 const OUString& rFace = rOption.GetString();
2931 OUString aFontName;
2932 sal_Int32 nPos = 0;
2933 while( nPos != -1 )
2934 {
2935 // font list separator: VCL = ';' HTML = ','
2936 std::u16string_view aFName = comphelper::string::strip(o3tl::getToken(rFace, 0, ',', nPos), ' ');
2937 aFontName = ScGlobal::addToken(aFontName, aFName, ';');
2938 }
2939 if ( !aFontName.isEmpty() )
2941 aFontName, OUString(), PITCH_DONTKNOW,
2942 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ) );
2943 }
2944 break;
2945 case HtmlOptionId::SIZE :
2946 {
2947 sal_uInt32 nSize = getLimitedValue< sal_uInt32 >( rOption.GetNumber(), 1, SC_HTML_FONTSIZES );
2949 }
2950 break;
2951 case HtmlOptionId::COLOR :
2952 {
2953 Color aColor;
2954 rOption.GetColor( aColor );
2956 }
2957 break;
2958 default: break;
2959 }
2960 }
2961}
2962
2964{
2965 if( mpDoc->GetDocumentShell() )
2966 {
2967 HTMLParser* pParser = static_cast< HTMLParser* >( rInfo.pParser );
2968
2969 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
2970 mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
2971 pParser->ParseMetaOptions(
2972 xDPS->getDocumentProperties(),
2974 }
2975}
2976
2978{
2979 mbTitleOn = true;
2980 maTitle.setLength(0);
2981}
2982
2984{
2985 if( !mbTitleOn )
2986 return;
2987
2988 OUString aTitle = maTitle.makeStringAndClear().trim();
2989 if (!aTitle.isEmpty() && mpDoc->GetDocumentShell())
2990 {
2991 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
2992 mpDoc->GetDocumentShell()->GetModel(), uno::UNO_QUERY_THROW);
2993
2994 xDPS->getDocumentProperties()->setTitle(aTitle);
2995 }
2996 InsertText( rInfo );
2997 mbTitleOn = false;
2998}
2999
3001{
3002 mpCurrTable = mpCurrTable->TableOn( rInfo );
3003}
3004
3006{
3007 mpCurrTable = mpCurrTable->TableOff( rInfo );
3008}
3009
3011{
3012 mpCurrTable = mpCurrTable->PreOn( rInfo );
3013}
3014
3016{
3017 mpCurrTable = mpCurrTable->PreOff( rInfo );
3018}
3019
3021{
3023}
3024
3025namespace {
3026
3030class CSSHandler: public orcus::css_handler
3031{
3032 typedef std::pair<std::string_view, std::string_view> SelectorName; // element : class
3033 typedef std::vector<SelectorName> SelectorNames;
3034
3035 SelectorNames maSelectorNames; // current selector names
3036 std::string_view maPropName; // current property name.
3037 std::string_view maPropValue; // current property value.
3038 ScHTMLStyles& mrStyles;
3039
3040public:
3041 explicit CSSHandler(ScHTMLStyles& rStyles):
3042 mrStyles(rStyles)
3043 {}
3044
3045 // selector name not starting with "." or "#" (i.e. element selectors)
3046 void simple_selector_type(std::string_view aElem)
3047 {
3048 std::string_view aClass{}; // class name not given - to be added in the "element global" storage
3049 SelectorName aName(aElem, aClass);
3050
3051 maSelectorNames.push_back(aName);
3052 }
3053
3054 // selector names starting with a "." (i.e. class selector)
3055 void simple_selector_class(std::string_view aClass)
3056 {
3057 std::string_view aElem{}; // no element given - should be added in the "global" storage
3058 SelectorName aName(aElem, aClass);
3059
3060 maSelectorNames.push_back(aName);
3061 }
3062
3063 // TODO: Add other selectors
3064
3065 void property_name(std::string_view aPropName)
3066 {
3067 maPropName = aPropName;
3068 }
3069
3070 void value(std::string_view aValue)
3071 {
3072 maPropValue = aValue;
3073 }
3074
3075 void end_block()
3076 {
3077 maSelectorNames.clear();
3078 }
3079
3080 void end_property()
3081 {
3082 for (const auto& rSelName : maSelectorNames)
3083 {
3084 // Add this property to the collection for each selector.
3085 std::string_view aElem = rSelName.first;
3086 std::string_view aClass = rSelName.second;
3087 OUString aName(maPropName.data(), maPropName.size(), RTL_TEXTENCODING_UTF8);
3088 OUString aValue(maPropValue.data(), maPropValue.size(), RTL_TEXTENCODING_UTF8);
3089 mrStyles.add(aElem.data(), aElem.size(), aClass.data(), aClass.size(), aName, aValue);
3090 }
3091 maPropName = std::string_view{};
3092 maPropValue = std::string_view{};
3093 }
3094
3095};
3096
3097}
3098
3099void ScHTMLQueryParser::ParseStyle(std::u16string_view rStrm)
3100{
3101 OString aStr = OUStringToOString(rStrm, RTL_TEXTENCODING_UTF8);
3102 CSSHandler aHdl(GetStyles());
3103 orcus::css_parser<CSSHandler> aParser(aStr, aHdl);
3104 try
3105 {
3106 aParser.parse();
3107 }
3108 catch (const orcus::parse_error& rOrcusParseError)
3109 {
3110 SAL_WARN("sc", "ScHTMLQueryParser::ParseStyle: " << rOrcusParseError.what());
3111 // TODO: Parsing of CSS failed. Do nothing for now.
3112 }
3113}
3114
3115IMPL_LINK( ScHTMLQueryParser, HTMLImportHdl, HtmlImportInfo&, rInfo, void )
3116{
3117 switch( rInfo.eState )
3118 {
3119 case HtmlImportState::Start:
3120 break;
3121
3122 case HtmlImportState::NextToken:
3123 ProcessToken( rInfo );
3124 break;
3125
3126 case HtmlImportState::InsertPara:
3127 mpCurrTable->InsertPara( rInfo );
3128 break;
3129
3130 case HtmlImportState::SetAttr:
3131 case HtmlImportState::InsertText:
3132 case HtmlImportState::InsertField:
3133 break;
3134
3135 case HtmlImportState::End:
3136 while( mpCurrTable->GetTableId() != SC_HTML_GLOBAL_TABLE )
3137 CloseTable( rInfo );
3138 break;
3139
3140 default:
3141 OSL_FAIL( "ScHTMLQueryParser::HTMLImportHdl - unknown ImportInfo::eState" );
3142 }
3143}
3144
3145/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
geometry::RealSize2D maSize
const Point maEnd
const SCCOL SCCOL_MAX
Definition: address.hxx:56
const SCROW SCROW_MAX
Definition: address.hxx:55
std::vector< Reference< XAnimationNode > >::iterator maIter
static OutputDevice * GetDefaultDevice()
ErrCode Read(SvStream &rInput, const OUString &rBaseURL, EETextFormat, SvKeyValueIterator *pHTTPHeaderAttrs=nullptr)
sal_Int32 GetTextLen() const
void SetHtmlImportHdl(const Link< HtmlImportInfo &, void > &rLink)
const Link< HtmlImportInfo &, void > & GetHtmlImportHdl() const
static GraphicFilter & GetGraphicFilter()
OUString GetImportFormatName(sal_uInt16 nFormat)
static ErrCode LoadGraphic(const OUString &rPath, const OUString &rFilter, Graphic &rGraphic, GraphicFilter *pFilter=nullptr, sal_uInt16 *pDeterminedFormat=nullptr)
const OUString & GetString() const
sal_uInt32 GetNumber() const
virtual bool ParseMetaOptions(const css::uno::Reference< css::document::XDocumentProperties > &, SvKeyValueIterator *)
static OUString GetAbsURL(std::u16string_view rTheBaseURIRef, OUString const &rTheRelURIRef, EncodeMechanism eEncodeMechanism=EncodeMechanism::WasEncoded, DecodeMechanism eDecodeMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
void setX(tools::Long nX)
void setY(tools::Long nY)
constexpr tools::Long X() const
@ UNINITIALIZED
Definition: address.hxx:220
SCTAB Tab() const
Definition: address.hxx:283
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SC_DLLPUBLIC bool Move(SCCOL nDeltaX, SCROW nDeltaY, SCTAB nDeltaZ, ScAddress &rErrorPos, const ScDocument &rDoc)
Definition: address.cxx:2280
void IncCol(SCCOL nDelta=1)
Definition: address.hxx:316
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
SCCOL Col() const
Definition: address.hxx:279
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC void ApplyAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem &rAttr)
Definition: document.cxx:4741
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1083
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:899
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
void NewActEntry(const ScEEParseEntry *)
Definition: eeimpars.cxx:655
SCCOL nColCnt
Definition: eeparser.hxx:110
ColWidthsMap maColWidths
Definition: eeparser.hxx:108
EditEngine * pEdit
Definition: eeparser.hxx:103
std::vector< std::shared_ptr< ScEEParseEntry > > maList
Definition: eeparser.hxx:106
std::shared_ptr< ScEEParseEntry > mxActEntry
Definition: eeparser.hxx:107
SCROW nRowMax
Definition: eeparser.hxx:113
SCROW nRowCnt
Definition: eeparser.hxx:111
SCCOL nColMax
Definition: eeparser.hxx:112
rtl::Reference< SfxItemPool > pPool
Definition: eeparser.hxx:104
static SC_DLLPUBLIC OUString addToken(std::u16string_view rTokenList, std::u16string_view rToken, sal_Unicode cSep, sal_Int32 nSepCount=1, bool bForceSep=false)
Adds the string rToken to rTokenList, using a list separator character.
Definition: global.cxx:705
The "global table" representing the entire HTML document.
Definition: htmlpars.hxx:559
ScHTMLGlobalTable(SfxItemPool &rPool, EditEngine &rEditEngine, std::vector< std::shared_ptr< ScEEParseEntry > > &rEEParseList, ScHTMLTableId &rnUnusedId, ScHTMLParser *pParser, const ScDocument &rDoc)
Definition: htmlpars.cxx:2746
void Recalc()
Recalculates sizes and resulting positions of all document entries.
Definition: htmlpars.cxx:2762
virtual ~ScHTMLGlobalTable() override
Definition: htmlpars.cxx:2758
ScRangeListRef xLockedList
Definition: htmlpars.hxx:160
void AnchorOn(HtmlImportInfo *)
Definition: htmlpars.cxx:1392
static void EntryEnd(ScEEParseEntry *, const ESelection &)
Definition: htmlpars.cxx:317
void ProcToken(HtmlImportInfo *)
Definition: htmlpars.cxx:1465
virtual ~ScHTMLLayoutParser() override
Definition: htmlpars.cxx:232
sal_uInt16 nColOffset
Definition: htmlpars.hxx:171
sal_uInt16 nOffsetTolerance
Definition: htmlpars.hxx:173
ScHTMLLayoutParser(EditEngine *, OUString aBaseURL, const Size &aPageSize, ScDocument *)
Definition: htmlpars.cxx:205
ScHTMLColOffset * pLocalColOffset
Definition: htmlpars.hxx:163
void Image(HtmlImportInfo *)
Definition: htmlpars.cxx:1266
sal_uInt16 nMaxTable
Definition: htmlpars.hxx:167
void NextRow(const HtmlImportInfo *)
Definition: htmlpars.cxx:333
virtual const ScHTMLTable * GetGlobalTable() const override
Returns the "global table" which contains the entire HTML document.
Definition: htmlpars.cxx:297
::std::stack< std::unique_ptr< ScHTMLTableStackEntry > > aTableStack
Definition: htmlpars.hxx:158
void TableOn(HtmlImportInfo *)
Definition: htmlpars.cxx:1011
sal_uInt16 nTable
Definition: htmlpars.hxx:166
sal_uInt16 GetWidth(const ScEEParseEntry *)
Definition: htmlpars.cxx:618
void TableRowOff(const HtmlImportInfo *)
Definition: htmlpars.cxx:1000
void TableRowOn(const HtmlImportInfo *)
Definition: htmlpars.cxx:993
std::unique_ptr< OuterMap > pTables
Definition: htmlpars.hxx:161
static bool SeekOffset(const ScHTMLColOffset *, sal_uInt16 nOffset, SCCOL *pCol, sal_uInt16 nOffsetTol)
Definition: htmlpars.cxx:344
void FontOn(HtmlImportInfo *)
Definition: htmlpars.cxx:1410
void Colonize(ScEEParseEntry *)
Definition: htmlpars.cxx:790
static void ModifyOffset(ScHTMLColOffset *, sal_uInt16 &nOldOffset, sal_uInt16 &nNewOffset, sal_uInt16 nOffsetTol)
Definition: htmlpars.cxx:403
void SkipLocked(ScEEParseEntry *, bool bJoin=true)
Definition: htmlpars.cxx:440
void CloseEntry(const HtmlImportInfo *)
Definition: htmlpars.cxx:818
bool IsAtBeginningOfText(const HtmlImportInfo *)
Definition: htmlpars.cxx:1402
sal_uInt16 GetWidthPixel(const HTMLOption &)
Definition: htmlpars.cxx:1372
void NewActEntry(const ScEEParseEntry *)
Definition: htmlpars.cxx:302
void TableDataOff(const HtmlImportInfo *)
Definition: htmlpars.cxx:1005
sal_uLong nFirstTableCell
Definition: htmlpars.hxx:164
ScHTMLColOffset maColOffset
Definition: htmlpars.hxx:162
void TableOff(const HtmlImportInfo *)
Definition: htmlpars.cxx:1111
virtual ErrCode Read(SvStream &, const OUString &rBaseURL) override
Definition: htmlpars.cxx:250
static void MakeCol(ScHTMLColOffset *, sal_uInt16 &nOffset, sal_uInt16 &nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol)
Definition: htmlpars.cxx:369
sal_uInt16 nColOffsetStart
Definition: htmlpars.hxx:172
static void MakeColNoRef(ScHTMLColOffset *, sal_uInt16 nOffset, sal_uInt16 nWidth, sal_uInt16 nOffsetTol, sal_uInt16 nWidthTol)
Definition: htmlpars.cxx:387
void ColOn(HtmlImportInfo *)
Definition: htmlpars.cxx:1358
void TableDataOn(HtmlImportInfo *)
Definition: htmlpars.cxx:900
sal_uInt16 nTableWidth
Definition: htmlpars.hxx:170
Base class for HTML parser classes.
Definition: htmlpars.hxx:79
ScHTMLParser(EditEngine *pEditEngine, ScDocument *pDoc)
The destination document.
Definition: htmlpars.cxx:188
sal_uInt32 maFontHeights[SC_HTML_FONTSIZES]
Definition: htmlpars.hxx:82
ScHTMLStyles & GetStyles()
Definition: htmlpars.hxx:91
ScDocument * mpDoc
Definition: htmlpars.hxx:83
virtual ~ScHTMLParser() override
Definition: htmlpars.cxx:201
ScDocument & GetDoc()
Definition: htmlpars.hxx:92
The HTML parser for data queries.
Definition: htmlpars.hxx:580
void PreOn(const HtmlImportInfo &rInfo)
Opens a new table based on preformatted text.
Definition: htmlpars.cxx:3010
void TitleOff(const HtmlImportInfo &rInfo)
Closes the title of the HTML document (</title> tag).
Definition: htmlpars.cxx:2983
void TableOff(const HtmlImportInfo &rInfo)
Closes the current table.
Definition: htmlpars.cxx:3005
ScHTMLTable * mpCurrTable
Contains the entire imported document.
Definition: htmlpars.hxx:626
virtual ~ScHTMLQueryParser() override
Definition: htmlpars.cxx:2782
virtual ErrCode Read(SvStream &rStrm, const OUString &rBaseURL) override
Definition: htmlpars.cxx:2786
void PreOff(const HtmlImportInfo &rInfo)
Closes the current preformatted text table.
Definition: htmlpars.cxx:3015
bool mbTitleOn
First unused table identifier.
Definition: htmlpars.hxx:628
void ParseStyle(std::u16string_view rStrm)
Definition: htmlpars.cxx:3099
OUStringBuffer maTitle
Definition: htmlpars.hxx:624
void ProcessToken(const HtmlImportInfo &rInfo)
Handles all possible tags in the HTML document.
Definition: htmlpars.cxx:2829
ScHTMLGlobalTablePtr mxGlobTable
The title of the document.
Definition: htmlpars.hxx:625
void FontOn(const HtmlImportInfo &rInfo)
Processes the <font> tag.
Definition: htmlpars.cxx:2921
ScHTMLQueryParser(EditEngine *pEditEngine, ScDocument *pDoc)
Definition: htmlpars.cxx:2772
void CloseTable(const HtmlImportInfo &rInfo)
Closes the current table, regardless on opening tag.
Definition: htmlpars.cxx:3020
void TitleOn()
Opens the title of the HTML document (<title> tag).
Definition: htmlpars.cxx:2977
void InsertText(const HtmlImportInfo &rInfo)
Inserts a text portion into current entry.
Definition: htmlpars.cxx:2914
virtual const ScHTMLTable * GetGlobalTable() const override
Returns the "global table" which contains the entire HTML document.
Definition: htmlpars.cxx:2824
void MetaOn(const HtmlImportInfo &rInfo)
Processes the <meta> tag.
Definition: htmlpars.cxx:2963
ScHTMLTableId mnUnusedId
Pointer to current table (performance).
Definition: htmlpars.hxx:627
void TableOn(const HtmlImportInfo &rInfo)
Opens a new table at the current position.
Definition: htmlpars.cxx:3000
Collection of HTML style data parsed from the content of <style> elements.
Definition: htmlpars.hxx:50
::std::map< OUString, PropsType > NamePropsType
Definition: htmlpars.hxx:52
void add(const char *pElemName, size_t nElemName, const char *pClassName, size_t nClassName, const OUString &aProp, const OUString &aValue)
Definition: htmlpars.cxx:75
const OUString & getPropertyValue(const OUString &rElem, const OUString &rClass, const OUString &rPropName) const
Find best-matching property value for given element and class names.
Definition: htmlpars.cxx:120
ElemsType m_ElemProps
element global properties (no class specified)
Definition: htmlpars.hxx:57
ScHTMLStyles()
just a persistent empty string.
Definition: htmlpars.cxx:73
NamePropsType m_GlobalProps
Definition: htmlpars.hxx:55
NamePropsType m_ElemGlobalProps
global properties (for a given class for all elements)
Definition: htmlpars.hxx:56
std::unordered_map< OUString, OUString > PropsType
Definition: htmlpars.hxx:51
const OUString maEmpty
element to class to properties (both element and class are given)
Definition: htmlpars.hxx:58
static void insertProp(NamePropsType &rProps, const OUString &aName, const OUString &aProp, const OUString &aValue)
Definition: htmlpars.cxx:165
A map of ScHTMLTable objects.
Definition: htmlpars.cxx:1696
ScHTMLTableStdMap maTables
Reference to parent table.
Definition: htmlpars.cxx:1707
ScHTMLTable & mrParentTable
Definition: htmlpars.cxx:1706
std::shared_ptr< ScHTMLTable > ScHTMLTablePtr
Definition: htmlpars.cxx:1698
ScHTMLTable * mpCurrTable
Container for all table objects.
Definition: htmlpars.cxx:1708
std::map< ScHTMLTableId, ScHTMLTablePtr > ScHTMLTableStdMap
Definition: htmlpars.cxx:1699
ScHTMLTableMap(ScHTMLTable &rParentTable)
Current table, used for fast search.
Definition: htmlpars.cxx:1731
ScHTMLTableStdMap::iterator iterator
Definition: htmlpars.cxx:1702
ScHTMLTable * FindTable(ScHTMLTableId nTableId, bool bDeep=true) const
Returns the specified table.
Definition: htmlpars.cxx:1737
ScHTMLTable * CreateTable(const HtmlImportInfo &rInfo, bool bPreFormText, const ScDocument &rDoc)
Inserts a new table into the container.
Definition: htmlpars.cxx:1758
ScHTMLTableStdMap::const_iterator const_iterator
Definition: htmlpars.cxx:1703
void SetCurrTable(ScHTMLTable *pTable) const
Sets a working table with its index for search optimization.
Definition: htmlpars.cxx:1727
const_iterator begin() const
Definition: htmlpars.cxx:1713
const_iterator end() const
Definition: htmlpars.cxx:1714
Stores data for one table in an HTML document.
Definition: htmlpars.hxx:327
ScHTMLTable * PreOn(const HtmlImportInfo &rInfo)
Starts a new table based on preformatted text (.
Definition: htmlpars.cxx:1990
EditEngine & mrEditEngine
List of all used cells.
Definition: htmlpars.hxx:538
static bool IsSpaceCharInfo(const HtmlImportInfo &rInfo)
Returns true, if import info represents a space character.
Definition: htmlpars.cxx:2294
void RowOn(const HtmlImportInfo &rInfo)
Starts next row (tag).
Definition: htmlpars.cxx:2001
ScHTMLTableId GetTableId() const
Returns the unique identifier of the table.
Definition: htmlpars.hxx:347
std::optional< SfxItemSet > moRowItemSet
Items for the entire table.
Definition: htmlpars.hxx:533
::std::unique_ptr< ScHTMLEntry > ScHTMLEntryPtr
Definition: htmlpars.hxx:455
ScHTMLEntryVector * mpCurrEntryVector
List of entries for each cell.
Definition: htmlpars.hxx:541
ScHTMLSize maSize
Cumulated cell counts for each HTML table column/row.
Definition: htmlpars.hxx:544
bool PushEntry(ScHTMLEntryPtr &rxEntry)
Tries to insert the entry into the current cell.
Definition: htmlpars.cxx:2319
ScRangeList maUsedCells
List of all vertically merged cells.
Definition: htmlpars.hxx:537
void CalcNeededDocSize(ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nCellSpan, SCCOLROW nRealDocSize)
Calculates and sets the resulting size the cell needs in the document.
Definition: htmlpars.cxx:2567
void ImplPushEntryToVector(ScHTMLEntryVector &rEntryVector, ScHTMLEntryPtr &rxEntry)
Pushes the passed entry into the list of the current cell.
Definition: htmlpars.cxx:2311
void InsertPara(const HtmlImportInfo &rInfo)
Inserts a new line, if in preformatted text, else does nothing.
Definition: htmlpars.cxx:1930
SvNumberFormatter * GetFormatTable()
Definition: htmlpars.cxx:2284
virtual ~ScHTMLTable()
Definition: htmlpars.cxx:1882
static void ProcessFormatOptions(SfxItemSet &rItemSet, const HtmlImportInfo &rInfo)
Inserts additional formatting options from import info into the item set.
Definition: htmlpars.cxx:2496
ScHTMLTable * mpParentTable
Definition: htmlpars.hxx:526
void ImplDataOn(const ScHTMLSize &rSpanSize)
Set internal states for entering a new table cell.
Definition: htmlpars.cxx:2473
void DataOn(const HtmlImportInfo &rInfo)
Starts the next cell (or tag).
Definition: htmlpars.cxx:2069
ScRangeList maVMergedCells
List of all horizontally merged cells.
Definition: htmlpars.hxx:536
ScHTMLTableMapPtr mxNestedTables
Pointer to parent table.
Definition: htmlpars.hxx:527
void DataOff(const HtmlImportInfo &rInfo)
Closes the current cell ( or tag).
Definition: htmlpars.cxx:2136
void InsertNewCell(const ScHTMLSize &rSpanSize)
Inserts a new cell in an unused position, starting from current cell position.
Definition: htmlpars.cxx:2398
ScRangeList maHMergedCells
Items for the current cell.
Definition: htmlpars.hxx:535
void BodyOff(const HtmlImportInfo &rInfo)
Closes the body of the HTML document (</body> tag).
Definition: htmlpars.cxx:2159
void FillEmptyCells()
Fills all empty cells in this and nested tables with dummy parse entries.
Definition: htmlpars.cxx:2583
ScHTMLEntryPtr CreateEntry() const
Creates and returns a new empty flying entry at position (0,0).
Definition: htmlpars.cxx:2299
void PutText(const HtmlImportInfo &rInfo)
Inserts a text portion into current entry.
Definition: htmlpars.cxx:1915
void SetDocSize(ScHTMLOrient eOrient, SCCOLROW nCellPos, SCCOLROW nSize)
Updates the document column/row size of the specified column or row.
Definition: htmlpars.cxx:2552
OUStringBuffer maCaptionBuffer
Caption name of the table from
Definition: htmlpars.hxx:530
void RecalcDocSize()
Recalculates the size of all columns/rows in the table, regarding nested tables.
Definition: htmlpars.cxx:2619
void ApplyCellBorders(ScDocument *pDoc, const ScAddress &rFirstPos) const
Applies border formatting to the passed document.
Definition: htmlpars.cxx:2240
ScHTMLPos maDocBasePos
Address of current cell to fill.
Definition: htmlpars.hxx:546
std::map< ScHTMLPos, ScHTMLEntryVector > maEntryMap
List that owns the parse entries (from ScEEParser).
Definition: htmlpars.hxx:540
void CaptionOn()
Processes the caption of the table ( tag).
Definition: htmlpars.cxx:1976
::std::vector< SCCOLROW > ScSizeVec
Definition: htmlpars.hxx:453
ScHTMLEntryPtr mxCurrEntry
Current entry vector from map for faster access.
Definition: htmlpars.hxx:542
void BreakOn()
Inserts a line break ( tag).
Definition: htmlpars.cxx:1939
const SfxItemSet & GetCurrItemSet() const
Returns the item set from cell, row, or table, depending on current state.
Definition: htmlpars.cxx:1886
bool mbCaptionOn
true = Insert empty line before current entry.
Definition: htmlpars.hxx:554
void HeadingOn()
Inserts a heading line (.
Definition: htmlpars.cxx:1945
void CreateNewEntry(const HtmlImportInfo &rInfo)
Creates a new flying entry.
Definition: htmlpars.cxx:2304
std::optional< SfxItemSet > moDataItemSet
Items for the current table row.
Definition: htmlpars.hxx:534
void InsertLeadingEmptyLine()
Inserts an empty line in front of the next entry.
Definition: htmlpars.cxx:1951
ScHTMLParser * mpParser
Resulting base address in a Calc document.
Definition: htmlpars.hxx:547
OUString maTableName
Table of nested HTML tables.
Definition: htmlpars.hxx:528
ScHTMLTable * PreOff(const HtmlImportInfo &rInfo)
Closes this table based on preformatted text ( tag).
Definition: htmlpars.cxx:1996
const ScHTMLPos & GetDocPos() const
Returns the resulting Calc position of the top left edge of the table.
Definition: htmlpars.hxx:419
void PutItem(const SfxPoolItem &rItem)
Puts the item into the item set of the current entry.
Definition: htmlpars.cxx:1908
ScHTMLTable(ScHTMLTable &rParentTable, const HtmlImportInfo &rInfo, bool bPreFormText, const ScDocument &rDoc)
Creates a new HTML table without content.
Definition: htmlpars.cxx:1810
void AnchorOn()
Processes a hyperlink ( tag).
Definition: htmlpars.cxx:1957
std::vector< std::shared_ptr< ScEEParseEntry > > & mrEEParseList
Edit engine (from ScEEParser).
Definition: htmlpars.hxx:539
void BodyOn(const HtmlImportInfo &rInfo)
Starts the body of the HTML document (<body> tag).
Definition: htmlpars.cxx:2144
void ImplDataOff()
Set internal states for leaving a table cell.
Definition: htmlpars.cxx:2485
ScHTMLPos maCurrCell
Size of the table.
Definition: htmlpars.hxx:545
bool mbPushEmptyLine
true = Inside of or .
Definition: htmlpars.hxx:553
ScHTMLTable * TableOn(const HtmlImportInfo &rInfo)
Starts a new table nested in this table (.
Definition: htmlpars.cxx:1965
ScSizeVec maCumSizes[2]
Working entry, not yet inserted in a list.
Definition: htmlpars.hxx:543
ScHTMLTable * FindNestedTable(ScHTMLTableId nTableId) const
Searches in all nested tables for the specified table.
Definition: htmlpars.cxx:1903
void RowOff(const HtmlImportInfo &rInfo)
Closes the current row (tag).
Definition: htmlpars.cxx:2012
bool mbPreFormText
true = Table borders on.
Definition: htmlpars.hxx:550
const ScDocument & mrDoc
Definition: htmlpars.hxx:548
void ImplRowOn()
Set internal states for a new table row.
Definition: htmlpars.cxx:2451
ScHTMLSize GetSpan(const ScHTMLPos &rCellPos) const
Returns the cell spanning of the specified cell.
Definition: htmlpars.cxx:1892
ScHTMLTable * CloseTable(const HtmlImportInfo &rInfo)
Closes this table (tag) or preformatted text ( tag).
Definition: htmlpars.cxx:2170
SCCOLROW GetDocSize(ScHTMLOrient eOrient, SCCOLROW nCellPos) const
Returns the resulting document row/column count of the specified HTML row/column.
Definition: htmlpars.cxx:2186
OUString maCaption
Table name from.
Definition: htmlpars.hxx:529
::std::vector< ScHTMLEntry * > ScHTMLEntryVector
Definition: htmlpars.hxx:454
void ImplRowOff()
Set internal states for leaving a table row.
Definition: htmlpars.cxx:2461
void RecalcDocPos(const ScHTMLPos &rBasePos)
Recalculates the position of all cell entries and nested tables.
Definition: htmlpars.cxx:2668
bool IsEmptyCell() const
Returns true, if the current cell does not contain an entry yet.
Definition: htmlpars.cxx:2289
SfxItemSet maTableItemSet
Unique identifier of this table.
Definition: htmlpars.hxx:532
ScHTMLTable * GetExistingTable(ScHTMLTableId nTableId) const
Tries to find a table from the table container.
Definition: htmlpars.cxx:2381
ScHTMLTable * InsertNestedTable(const HtmlImportInfo &rInfo, bool bPreFormText)
Inserts a nested table in the current cell at the specified position.
Definition: htmlpars.cxx:2389
ScHTMLTable * TableOff(const HtmlImportInfo &rInfo)
Closes this table (tag).
Definition: htmlpars.cxx:1971
bool mbBorderOn
Definition: htmlpars.hxx:549
void CaptionOff()
Processes the caption of the table ( tag).
Definition: htmlpars.cxx:1982
bool mbRowOn
true = Table from preformatted text (
Definition: htmlpars.hxx:551
void PushTableEntry(ScHTMLTableId nTableId)
Pushes a new entry into current cell which references a nested table.
Definition: htmlpars.cxx:2371
void GetDocRange(ScRange &rRange) const
Calculates the current Calc document area of this table.
Definition: htmlpars.cxx:2229
bool mbDataOn
true = Inside of .
Definition: htmlpars.hxx:552
const ScRange * Find(const ScAddress &) const
Definition: rangelst.cxx:1027
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:152
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1137
size_t size() const
Definition: rangelst.hxx:89
ScAddress aEnd
Definition: address.hxx:498
bool Intersects(const ScRange &rRange) const
Definition: address.hxx:734
ScAddress aStart
Definition: address.hxx:497
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
bool IsLoading() const
SvKeyValueIterator * GetHeaderAttributes()
css::uno::Reference< css::frame::XModel3 > GetModel() const
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
sal_uInt32 GetEntryKey(std::u16string_view sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
static const sal_Int16 Medium
static const sal_Int16 Hairline
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
const Value & back() const
const_iterator begin() const
std::vector< Value >::const_iterator const_iterator
const_iterator find(const Value &x) const
bool empty() const
const_iterator end() const
size_type size() const
const Value & front() const
std::pair< const_iterator, bool > insert(Value &&x)
T * get() const
int nCount
const char * pS
FormulaCommand pE
const char nHorizontal
Definition: eeparser.hxx:35
const char nVertical
Definition: eeparser.hxx:36
#define ERRCODE_NONE
LINESTYLE_SINGLE
PITCH_DONTKNOW
ITALIC_NORMAL
FAMILY_DONTKNOW
WEIGHT_BOLD
SotClipboardFormatId & operator++(SotClipboardFormatId &eFormat)
#define OOO_STRING_SVTOOLS_HTML_AL_left
#define OOO_STRING_SVTOOLS_HTML_VA_middle
#define OOO_STRING_SVTOOLS_HTML_VA_bottom
#define OOO_STRING_SVTOOLS_HTML_AL_center
#define OOO_STRING_SVTOOLS_HTML_VA_top
#define OOO_STRING_SVTOOLS_HTML_AL_right
#define OOO_STRING_SVTOOLS_HTML_META_content_type
IMPL_LINK(ScHTMLLayoutParser, HTMLImportHdl, HtmlImportInfo &, rInfo, void)
Definition: htmlpars.cxx:858
static Type getLimitedValue(const Type &rValue, const Type &rMin, const Type &rMax)
Definition: htmlpars.cxx:1633
const ScHTMLTableId SC_HTML_NO_TABLE
Used as table index for normal (non-table) entries in ScHTMLEntry structs.
Definition: htmlpars.hxx:232
o3tl::sorted_vector< sal_uLong > ScHTMLColOffset
Definition: htmlpars.hxx:98
::std::map< sal_uInt16, InnerMap * > OuterMap
Definition: htmlpars.hxx:150
ScHTMLOrient
Declares the orientation in or for a table: column or row.
Definition: htmlpars.hxx:225
@ tdCol
Definition: htmlpars.hxx:225
@ tdRow
Definition: htmlpars.hxx:225
::std::map< SCROW, SCROW > InnerMap
Definition: htmlpars.hxx:146
const sal_uInt32 SC_HTML_FONTSIZES
Definition: htmlpars.hxx:35
const ScHTMLTableId SC_HTML_GLOBAL_TABLE
Identifier of the "global table" (the entire HTML document).
Definition: htmlpars.hxx:230
const sal_uInt16 SC_HTML_OFFSET_TOLERANCE_SMALL
Definition: htmlpars.hxx:38
const sal_uInt16 SC_HTML_OFFSET_TOLERANCE_LARGE
Definition: htmlpars.hxx:39
sal_uInt16 ScHTMLTableId
Type for a unique identifier for each table.
Definition: htmlpars.hxx:228
sal_Int32 nIndex
OUString aName
void * p
sal_Int64 n
sal_uInt16 nPos
#define SAL_WARN(area, stream)
aStr
aBuf
OString strip(const OString &rIn, char c)
Type
int i
void SvStream & rStrm
OUString aPropName
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
long Long
::std::vector< HTMLOption > HTMLOptions
constexpr TypedWhichId< SvxFontHeightItem > ATTR_FONT_HEIGHT(101)
constexpr TypedWhichId< SvxPostureItem > ATTR_FONT_POSTURE(103)
constexpr TypedWhichId< SvxWeightItem > ATTR_FONT_WEIGHT(102)
constexpr TypedWhichId< SvxColorItem > ATTR_FONT_COLOR(109)
constexpr TypedWhichId< SvxBrushItem > ATTR_BACKGROUND(148)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
constexpr TypedWhichId< SvxBoxItem > ATTR_BORDER(150)
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
constexpr TypedWhichId< SvxVerJustifyItem > ATTR_VER_JUSTIFY(132)
constexpr TypedWhichId< SvxFontItem > ATTR_FONT(100)
constexpr TypedWhichId< SvxUnderlineItem > ATTR_FONT_UNDERLINE(104)
sal_uIntPtr sal_uLong
bool HasRange() const
sal_Int32 nStartPara
sal_Int32 nEndPos
sal_Int32 nStartPos
sal_Int32 nEndPara
SvParser< HtmlTokenId > * pParser
ESelection aSelection
HtmlTokenId nToken
OUString aText
SCCOL nColOverlap
Definition: eeparser.hxx:69
ESelection aSel
Definition: eeparser.hxx:56
bool bEntirePara
Definition: eeparser.hxx:74
sal_uInt16 nTab
Definition: eeparser.hxx:67
OUString aAltText
Definition: eeparser.hxx:63
SCROW nRowOverlap
Definition: eeparser.hxx:70
A single entry containing a line of text or representing a table.
Definition: htmlpars.hxx:274
void AdjustStart(const HtmlImportInfo &rInfo)
Sets start point of the entry selection to the start of the import info object.
Definition: htmlpars.cxx:1649
bool HasContents() const
Returns true, if the entry has any content to be imported.
Definition: htmlpars.cxx:1644
ScHTMLEntry(const SfxItemSet &rItemSet, ScHTMLTableId nTableId=SC_HTML_NO_TABLE)
Definition: htmlpars.cxx:1636
bool IsTable() const
Returns true, if the entry represents a table.
Definition: htmlpars.hxx:285
bool mbImportAlways
Definition: htmlpars.hxx:304
ScHTMLTableId GetTableId() const
Returns true, if the entry represents a table.
Definition: htmlpars.hxx:287
void AdjustEnd(const HtmlImportInfo &rInfo)
Sets end point of the entry selection to the end of the import info object.
Definition: htmlpars.cxx:1662
void Strip(const EditEngine &rEditEngine)
Deletes leading and trailing empty paragraphs from the entry.
Definition: htmlpars.cxx:1672
SfxItemSet & GetItemSet()
Returns read/write access to the item set of this entry.
Definition: htmlpars.hxx:299
Point aSpace
Definition: eeparser.hxx:42
OUString aURL
Definition: eeparser.hxx:40
OUString aFilterName
Definition: eeparser.hxx:43
Size aSize
Definition: eeparser.hxx:41
std::optional< Graphic > oGraphic
Definition: eeparser.hxx:45
A 2D cell position in an HTML table.
Definition: htmlpars.hxx:236
ScAddress MakeAddr() const
Definition: htmlpars.hxx:251
SCCOL mnCol
Definition: htmlpars.hxx:237
SCCOLROW Get(ScHTMLOrient eOrient) const
Definition: htmlpars.hxx:245
SCROW mnRow
Definition: htmlpars.hxx:238
A 2D cell size in an HTML table.
Definition: htmlpars.hxx:262
void Set(SCCOL nCols, SCROW nRows)
Definition: htmlpars.hxx:268
SCROW mnRows
Definition: htmlpars.hxx:264
SCCOL mnCols
Definition: htmlpars.hxx:263
ScHTMLTableAutoId(ScHTMLTableId &rnUnusedId)
Reference to global unused identifier variable.
Definition: htmlpars.cxx:1803
ScHTMLTableId & mrnUnusedId
The created unique table identifier.
Definition: htmlpars.hxx:311
SvxCellHorJustify
SvxCellVerJustify
sal_uInt16 sal_Unicode
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
SvNumFormatType
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND