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 <com/sun/star/form/FormSubmitEncoding.hpp>
21 #include <com/sun/star/form/FormSubmitMethod.hpp>
22 #include <com/sun/star/form/FormButtonType.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/script/XEventAttacherManager.hpp>
25 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
26 #include <com/sun/star/form/XFormsSupplier.hpp>
27 #include <com/sun/star/form/XForm.hpp>
28 #include <com/sun/star/form/FormComponentType.hpp>
29 #include <com/sun/star/awt/XTextLayoutConstrains.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <hintids.hxx>
32 #include <o3tl/any.hxx>
33 #include <rtl/math.hxx>
34 #include <vcl/svapp.hxx>
35 #include <svl/macitem.hxx>
36 #include <svtools/htmlout.hxx>
37 #include <svtools/htmlkywd.hxx>
38 #include <svl/urihelper.hxx>
39 #include <vcl/unohelp.hxx>
40 #include <svx/svdouno.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/colritem.hxx>
43 #include <editeng/fhgtitem.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/wghtitem.hxx>
46 #include <editeng/postitem.hxx>
47 #include <editeng/udlnitem.hxx>
48 #include <editeng/crossedoutitem.hxx>
49 #include <osl/diagnose.h>
50 #include <docsh.hxx>
51 #include <fmtanchr.hxx>
52 #include <viewsh.hxx>
53 #include <pam.hxx>
54 #include <doc.hxx>
55 #include <IDocumentLayoutAccess.hxx>
56 #include <IDocumentDrawModelAccess.hxx>
57 #include "wrthtml.hxx"
58 #include "htmlfly.hxx"
59 #include "htmlform.hxx"
60 #include <frmfmt.hxx>
61 #include <frameformats.hxx>
62 #include <memory>
63 
64 using namespace ::com::sun::star;
65 
66 const HtmlFrmOpts HTML_FRMOPTS_CONTROL   =
67     HtmlFrmOpts::NONE;
68 const HtmlFrmOpts HTML_FRMOPTS_CONTROL_CSS1  =
69     HtmlFrmOpts::SAlign |
70     HtmlFrmOpts::SSize |
71     HtmlFrmOpts::SSpace |
72     HtmlFrmOpts::BrClear;
73 const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL   =
74     HtmlFrmOpts::Align |
75     HtmlFrmOpts::BrClear;
76 const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL_CSS1 =
77     HtmlFrmOpts::SAlign |
78     HtmlFrmOpts::SSpace;
79 
lcl_html_outEvents(SvStream & rStrm,const uno::Reference<form::XFormComponent> & rFormComp,bool bCfgStarBasic,rtl_TextEncoding eDestEnc,OUString * pNonConvertableChars)80 static void lcl_html_outEvents( SvStream& rStrm,
81                          const uno::Reference< form::XFormComponent >& rFormComp,
82                          bool bCfgStarBasic,
83                          rtl_TextEncoding eDestEnc,
84                          OUString *pNonConvertableChars )
85 {
86     uno::Reference< uno::XInterface > xParentIfc = rFormComp->getParent();
87     OSL_ENSURE( xParentIfc.is(), "lcl_html_outEvents: no parent interface" );
88     if( !xParentIfc.is() )
89         return;
90     uno::Reference< container::XIndexAccess > xIndexAcc( xParentIfc, uno::UNO_QUERY );
91     uno::Reference< script::XEventAttacherManager > xEventManager( xParentIfc,
92                                                               uno::UNO_QUERY );
93     if( !xIndexAcc.is() || !xEventManager.is() )
94         return;
95 
96     // and search for the position of the ControlModel within
97     sal_Int32 nCount = xIndexAcc->getCount(), nPos;
98     for( nPos = 0 ; nPos < nCount; nPos++ )
99     {
100         uno::Any aTmp = xIndexAcc->getByIndex(nPos);
101         if( auto x1 = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp) )
102 
103         {
104             if( rFormComp == *x1 )
105                 break;
106         }
107         else if( auto x2 = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) )
108         {
109             if( rFormComp == *x2 )
110                 break;
111         }
112         else
113         {
114             OSL_ENSURE( false, "lcl_html_outEvents: wrong reflection" );
115         }
116     }
117 
118     if( nPos == nCount )
119         return;
120 
121     const uno::Sequence< script::ScriptEventDescriptor > aDescs =
122             xEventManager->getScriptEvents( nPos );
123     if( !aDescs.hasElements() )
124         return;
125 
126     for( const script::ScriptEventDescriptor& rDesc : aDescs )
127     {
128         ScriptType eScriptType = EXTENDED_STYPE;
129         OUString aScriptType( rDesc.ScriptType );
130         if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_JAVASCRIPT) )
131             eScriptType = JAVASCRIPT;
132         else if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_STARBASIC ) )
133             eScriptType = STARBASIC;
134         if( JAVASCRIPT != eScriptType && !bCfgStarBasic )
135             continue;
136 
137         OUString sListener( rDesc.ListenerType );
138         if (!sListener.isEmpty())
139         {
140             const sal_Int32 nIdx { sListener.lastIndexOf('.')+1 };
141             if (nIdx>0)
142             {
143                 if (nIdx<sListener.getLength())
144                 {
145                     sListener = sListener.copy(nIdx);
146                 }
147                 else
148                 {
149                     sListener.clear();
150                 }
151             }
152         }
153         OUString sMethod( rDesc.EventMethod );
154 
155         const char *pOpt = nullptr;
156         for( int j=0; aEventListenerTable[j]; j++ )
157         {
158             if( sListener.equalsAscii( aEventListenerTable[j] ) &&
159                 sMethod.equalsAscii( aEventMethodTable[j] ) )
160             {
161                 pOpt = (STARBASIC==eScriptType ? aEventSDOptionTable
162                                                : aEventOptionTable)[j];
163                 break;
164             }
165         }
166 
167         OString sOut = " ";
168         if( pOpt && (EXTENDED_STYPE != eScriptType ||
169                      rDesc.AddListenerParam.isEmpty()) )
170             sOut += pOpt;
171         else
172         {
173             sOut += OOO_STRING_SVTOOLS_HTML_O_sdevent +
174                 OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" +
175                 OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US);
176         }
177         sOut += "=\"";
178         rStrm.WriteOString( sOut );
179         HTMLOutFuncs::Out_String( rStrm, rDesc.ScriptCode, eDestEnc, pNonConvertableChars );
180         rStrm.WriteChar( '\"' );
181         if( EXTENDED_STYPE == eScriptType &&
182             !rDesc.AddListenerParam.isEmpty() )
183         {
184             sOut = " " OOO_STRING_SVTOOLS_HTML_O_sdaddparam +
185                 OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" +
186                 OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US) + "=\"";
187             rStrm.WriteOString( sOut );
188             HTMLOutFuncs::Out_String( rStrm, rDesc.AddListenerParam,
189                                       eDestEnc, pNonConvertableChars );
190             rStrm.WriteChar( '\"' );
191         }
192     }
193 }
194 
lcl_html_isHTMLControl(sal_Int16 nClassId)195 static bool lcl_html_isHTMLControl( sal_Int16 nClassId )
196 {
197     bool bRet = false;
198 
199     switch( nClassId )
200     {
201     case form::FormComponentType::TEXTFIELD:
202     case form::FormComponentType::COMMANDBUTTON:
203     case form::FormComponentType::RADIOBUTTON:
204     case form::FormComponentType::CHECKBOX:
205     case form::FormComponentType::LISTBOX:
206     case form::FormComponentType::IMAGEBUTTON:
207     case form::FormComponentType::FILECONTROL:
208         bRet = true;
209         break;
210     }
211 
212     return bRet;
213 }
214 
HasControls() const215 bool SwHTMLWriter::HasControls() const
216 {
217     sal_uInt32 nStartIdx = m_pCurrentPam->GetPoint()->nNode.GetIndex();
218     size_t i = 0;
219 
220     // Skip all controls in front of the current paragraph
221     while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx )
222         ++i;
223 
224     return i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx == nStartIdx;
225 }
226 
OutForm(bool bTag_On,const SwStartNode * pStartNd)227 void SwHTMLWriter::OutForm( bool bTag_On, const SwStartNode *pStartNd )
228 {
229     if( m_bPreserveForm )   // we are in a table or an area with form spanned over it
230         return;
231 
232     if( !bTag_On )
233     {
234         // end the form when all controls are output
235         if( mxFormComps.is() &&
236             mxFormComps->getCount() == m_nFormCntrlCnt )
237         {
238             OutForm( false, mxFormComps );
239             mxFormComps.clear();
240         }
241         return;
242     }
243 
244     uno::Reference< container::XIndexContainer > xNewFormComps;
245     sal_uInt32 nStartIdx = pStartNd ? pStartNd->GetIndex()
246                                     : m_pCurrentPam->GetPoint()->nNode.GetIndex();
247 
248     // skip controls before the interesting area
249     size_t i = 0;
250     while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx )
251         ++i;
252 
253     if( !pStartNd )
254     {
255         // Check for a single node: there it's only interesting, if there is
256         // a control for the node and to which form it belongs.
257         if( i < m_aHTMLControls.size() &&
258             m_aHTMLControls[i]->nNdIdx == nStartIdx )
259             xNewFormComps = m_aHTMLControls[i]->xFormComps;
260     }
261     else
262     {
263         // we iterate over a table/an area: we're interested in:
264         // - if there are controls with different start nodes
265         // - if there is a form, with controls which aren't all in the table/area
266 
267         uno::Reference< container::XIndexContainer > xCurrentFormComps;// current form in table
268         const SwStartNode *pCurrentStNd = nullptr; // and the start node of a Control
269         sal_Int32 nCurrentCtrls = 0;   // and the found controls in it
270         sal_uInt32 nEndIdx =  pStartNd->EndOfSectionIndex();
271         for( ; i < m_aHTMLControls.size() &&
272             m_aHTMLControls[i]->nNdIdx <= nEndIdx; i++ )
273         {
274             const SwStartNode *pCntrlStNd =
275                 m_pDoc->GetNodes()[m_aHTMLControls[i]->nNdIdx]->StartOfSectionNode();
276 
277             if( xCurrentFormComps.is() )
278             {
279                 // already inside a form ...
280                 if( xCurrentFormComps==m_aHTMLControls[i]->xFormComps )
281                 {
282                     // ... and the control is also inside ...
283                     if( pCurrentStNd!=pCntrlStNd )
284                     {
285                         // ... but it's inside another cell:
286                         // Then open a form above the table
287                         xNewFormComps = xCurrentFormComps;
288                         break;
289                     }
290                     nCurrentCtrls = nCurrentCtrls + m_aHTMLControls[i]->nCount;
291                 }
292                 else
293                 {
294                     // ... but the Control is in another cell:
295                     // There we act as if we open a new from and continue searching.
296                     xCurrentFormComps = m_aHTMLControls[i]->xFormComps;
297                     pCurrentStNd = pCntrlStNd;
298                     nCurrentCtrls = m_aHTMLControls[i]->nCount;
299                 }
300             }
301             else
302             {
303                 // We aren't in a form:
304                 // There we act as if we open a form.
305                 xCurrentFormComps = m_aHTMLControls[i]->xFormComps;
306                 pCurrentStNd = pCntrlStNd;
307                 nCurrentCtrls = m_aHTMLControls[i]->nCount;
308             }
309         }
310         if( !xNewFormComps.is() && xCurrentFormComps.is() &&
311             nCurrentCtrls != xCurrentFormComps->getCount() )
312         {
313             // A form should be opened in the table/area which isn't completely
314             // inside the table. Then we must also now open the form.
315             xNewFormComps = xCurrentFormComps;
316         }
317     }
318 
319     if( !(xNewFormComps.is() &&
320         (!mxFormComps.is() || xNewFormComps != mxFormComps)) )
321         return;
322 
323     // A form should be opened ...
324     if( mxFormComps.is() )
325     {
326         // ... but a form is still open: That is in every case an error,
327         // but we'll close the old form nevertheless.
328         OutForm( false, mxFormComps );
329 
330         //!!!nWarn = 1; // Control will be assigned to wrong form
331     }
332 
333     mxFormComps = xNewFormComps;
334 
335     OutForm( true, mxFormComps );
336     uno::Reference< beans::XPropertySet >  xTmp;
337     OutHiddenControls( mxFormComps, xTmp );
338 }
339 
OutHiddenForms()340 void SwHTMLWriter::OutHiddenForms()
341 {
342     // Without DrawModel there can't be controls. Then you also can't access the
343     // document via UNO, because otherwise a DrawModel would be created.
344     if( !m_pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
345         return;
346 
347     SwDocShell *pDocSh = m_pDoc->GetDocShell();
348     if( !pDocSh )
349         return;
350 
351     uno::Reference< drawing::XDrawPageSupplier > xDPSupp( pDocSh->GetBaseModel(),
352                                                      uno::UNO_QUERY );
353     OSL_ENSURE( xDPSupp.is(), "XTextDocument not received from XModel" );
354     uno::Reference< drawing::XDrawPage > xDrawPage = xDPSupp->getDrawPage();
355 
356     OSL_ENSURE( xDrawPage.is(), "XDrawPage not received" );
357     if( !xDrawPage.is() )
358         return;
359 
360     uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage, uno::UNO_QUERY );
361     OSL_ENSURE( xFormsSupplier.is(),
362             "XFormsSupplier not received from XDrawPage" );
363 
364     uno::Reference< container::XNameContainer > xTmp = xFormsSupplier->getForms();
365     OSL_ENSURE( xTmp.is(), "XForms not received" );
366     uno::Reference< container::XIndexContainer > xForms( xTmp, uno::UNO_QUERY );
367     OSL_ENSURE( xForms.is(), "XForms without container::XIndexContainer?" );
368 
369     sal_Int32 nCount = xForms->getCount();
370     for( sal_Int32 i=0; i<nCount; i++)
371     {
372         uno::Any aTmp = xForms->getByIndex( i );
373         if( auto x = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) )
374             OutHiddenForm( *x );
375         else
376         {
377             OSL_ENSURE( false, "OutHiddenForms: wrong reflection" );
378         }
379     }
380 }
381 
OutHiddenForm(const uno::Reference<form::XForm> & rForm)382 void SwHTMLWriter::OutHiddenForm( const uno::Reference< form::XForm > & rForm )
383 {
384     uno::Reference< container::XIndexContainer > xFormComps( rForm, uno::UNO_QUERY );
385     if( !xFormComps.is() )
386         return;
387 
388     sal_Int32 nCount = xFormComps->getCount();
389     bool bHiddenOnly = nCount > 0, bHidden = false;
390     for( sal_Int32 i=0; i<nCount; i++ )
391     {
392         uno::Any aTmp = xFormComps->getByIndex( i );
393         auto xFormComp = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(
394             aTmp);
395         OSL_ENSURE( xFormComp, "OutHiddenForm: wrong reflection" );
396         if( !xFormComp )
397             continue;
398 
399         uno::Reference< form::XForm > xForm( *xFormComp, uno::UNO_QUERY );
400         if( xForm.is() )
401             OutHiddenForm( xForm );
402 
403         if( bHiddenOnly )
404         {
405             uno::Reference< beans::XPropertySet >  xPropSet( *xFormComp, uno::UNO_QUERY );
406             OUString sPropName("ClassId");
407             if( xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
408             {
409                 uno::Any aAny2 = xPropSet->getPropertyValue( sPropName );
410                 if( auto n = o3tl::tryAccess<sal_Int16>(aAny2) )
411                 {
412                     if( form::FormComponentType::HIDDENCONTROL == *n )
413                         bHidden = true;
414                     else if( lcl_html_isHTMLControl( *n ) )
415                         bHiddenOnly = false;
416                 }
417             }
418         }
419     }
420 
421     if( bHidden && bHiddenOnly )
422     {
423         OutForm( true, xFormComps );
424         uno::Reference< beans::XPropertySet > xTmp;
425         OutHiddenControls( xFormComps, xTmp );
426         OutForm( false, xFormComps );
427     }
428 }
429 
OutForm(bool bOn,const uno::Reference<container::XIndexContainer> & rFormComps)430 void SwHTMLWriter::OutForm( bool bOn,
431                 const uno::Reference< container::XIndexContainer > & rFormComps )
432 {
433     m_nFormCntrlCnt = 0;
434 
435     if( !bOn )
436     {
437         DecIndentLevel(); // indent content of form
438         if( m_bLFPossible )
439             OutNewLine();
440         HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_form), false );
441         m_bLFPossible = true;
442 
443         return;
444     }
445 
446     // the new form is opened
447     if( m_bLFPossible )
448         OutNewLine();
449     OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_form;
450 
451     uno::Reference< beans::XPropertySet > xFormPropSet( rFormComps, uno::UNO_QUERY );
452 
453     uno::Any aTmp = xFormPropSet->getPropertyValue( "Name" );
454     if( auto s = o3tl::tryAccess<OUString>(aTmp) )
455     {
456         if( !s->isEmpty() )
457         {
458             sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
459             Strm().WriteOString( sOut );
460             HTMLOutFuncs::Out_String( Strm(), *s,
461                                       m_eDestEnc, &m_aNonConvertableCharacters );
462             sOut = "\"";
463         }
464     }
465 
466     aTmp = xFormPropSet->getPropertyValue( "TargetURL" );
467     if( auto s = o3tl::tryAccess<OUString>(aTmp) )
468     {
469         if ( !s->isEmpty() )
470         {
471             sOut += " " OOO_STRING_SVTOOLS_HTML_O_action "=\"";
472             Strm().WriteOString( sOut );
473             OUString aURL
474                 = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *s);
475             HTMLOutFuncs::Out_String( Strm(), aURL, m_eDestEnc, &m_aNonConvertableCharacters );
476             sOut = "\"";
477         }
478     }
479 
480     aTmp = xFormPropSet->getPropertyValue( "SubmitMethod" );
481     if( auto eMethod = o3tl::tryAccess<form::FormSubmitMethod>(aTmp) )
482     {
483         if( form::FormSubmitMethod_POST==*eMethod )
484         {
485             sOut += " " OOO_STRING_SVTOOLS_HTML_O_method "=\""
486                 OOO_STRING_SVTOOLS_HTML_METHOD_post "\"";
487         }
488     }
489     aTmp = xFormPropSet->getPropertyValue( "SubmitEncoding" );
490     if( auto eEncType = o3tl::tryAccess<form::FormSubmitEncoding>(aTmp) )
491     {
492         const char *pStr = nullptr;
493         switch( *eEncType )
494         {
495         case form::FormSubmitEncoding_MULTIPART:
496             pStr = OOO_STRING_SVTOOLS_HTML_ET_multipart;
497             break;
498         case form::FormSubmitEncoding_TEXT:
499             pStr = OOO_STRING_SVTOOLS_HTML_ET_text;
500             break;
501         default:
502             ;
503         }
504 
505         if( pStr )
506         {
507             sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_enctype "=\"") +
508                 pStr + "\"";
509         }
510     }
511 
512     aTmp = xFormPropSet->getPropertyValue( "TargetFrame" );
513     if( auto s = o3tl::tryAccess<OUString>(aTmp) )
514     {
515         if (!s->isEmpty() )
516         {
517             sOut += " " OOO_STRING_SVTOOLS_HTML_O_target "=\"";
518             Strm().WriteOString( sOut );
519             HTMLOutFuncs::Out_String( Strm(), *s,
520                                       m_eDestEnc, &m_aNonConvertableCharacters );
521             sOut = "\"";
522         }
523     }
524 
525     Strm().WriteOString( sOut );
526     uno::Reference< form::XFormComponent > xFormComp( rFormComps, uno::UNO_QUERY );
527     lcl_html_outEvents( Strm(), xFormComp, m_bCfgStarBasic, m_eDestEnc, &m_aNonConvertableCharacters );
528     Strm().WriteChar( '>' );
529 
530     IncIndentLevel(); // indent content of form
531     m_bLFPossible = true;
532 }
533 
OutHiddenControls(const uno::Reference<container::XIndexContainer> & rFormComps,const uno::Reference<beans::XPropertySet> & rPropSet)534 void SwHTMLWriter::OutHiddenControls(
535         const uno::Reference< container::XIndexContainer > & rFormComps,
536         const uno::Reference< beans::XPropertySet > & rPropSet )
537 {
538     sal_Int32 nCount = rFormComps->getCount();
539     sal_Int32 nPos = 0;
540     if( rPropSet.is() )
541     {
542         bool bDone = false;
543 
544         uno::Reference< form::XFormComponent > xFC( rPropSet, uno::UNO_QUERY );
545         for( nPos=0; !bDone && nPos < nCount; nPos++ )
546         {
547             uno::Any aTmp = rFormComps->getByIndex( nPos );
548             auto x = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp);
549             OSL_ENSURE( x,
550                     "OutHiddenControls: wrong reflection" );
551             bDone = x && *x == xFC;
552         }
553     }
554 
555     for( ; nPos < nCount; nPos++ )
556     {
557         uno::Any aTmp = rFormComps->getByIndex( nPos );
558         auto xFC = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp);
559         OSL_ENSURE( xFC,
560                 "OutHiddenControls: wrong reflection" );
561         if( !xFC )
562             continue;
563         uno::Reference< beans::XPropertySet > xPropSet( *xFC, uno::UNO_QUERY );
564 
565         OUString sPropName = "ClassId";
566         if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
567             continue;
568 
569         aTmp = xPropSet->getPropertyValue( sPropName );
570         auto n = o3tl::tryAccess<sal_Int16>(aTmp);
571         if( !n )
572             continue;
573 
574         if( form::FormComponentType::HIDDENCONTROL == *n )
575         {
576             if( m_bLFPossible )
577                 OutNewLine( true );
578             OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_input " "
579                 OOO_STRING_SVTOOLS_HTML_O_type "=\""
580                 OOO_STRING_SVTOOLS_HTML_IT_hidden "\"";
581 
582             aTmp = xPropSet->getPropertyValue( "Name" );
583             if( auto s = o3tl::tryAccess<OUString>(aTmp) )
584             {
585                 if( !s->isEmpty() )
586                 {
587                     sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
588                     Strm().WriteOString( sOut );
589                     HTMLOutFuncs::Out_String( Strm(), *s,
590                                               m_eDestEnc, &m_aNonConvertableCharacters );
591                     sOut = "\"";
592                 }
593             }
594             aTmp = xPropSet->getPropertyValue( "HiddenValue" );
595             if( auto s = o3tl::tryAccess<OUString>(aTmp) )
596             {
597                 if( !s->isEmpty() )
598                 {
599                     sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
600                     Strm().WriteOString( sOut );
601                     HTMLOutFuncs::Out_String( Strm(), *s,
602                                               m_eDestEnc, &m_aNonConvertableCharacters );
603                     sOut = "\"";
604                 }
605             }
606             sOut += ">";
607             Strm().WriteOString( sOut );
608 
609             m_nFormCntrlCnt++;
610         }
611         else if( lcl_html_isHTMLControl( *n ) )
612         {
613             break;
614         }
615     }
616 }
617 
618 // here are the output routines, thus the form::Forms are bundled:
619 
GetHTMLControl(const SwDrawFrameFormat & rFormat)620 const SdrObject *SwHTMLWriter::GetHTMLControl( const SwDrawFrameFormat& rFormat )
621 {
622     // it must be a Draw-Format
623     OSL_ENSURE( RES_DRAWFRMFMT == rFormat.Which(),
624             "GetHTMLControl only allow for Draw-Formats" );
625 
626     // Look if a SdrObject exists for it
627     const SdrObject *pObj = rFormat.FindSdrObject();
628     if( !pObj || SdrInventor::FmForm != pObj->GetObjInventor() )
629         return nullptr;
630 
631     const SdrUnoObj& rFormObj = dynamic_cast<const SdrUnoObj&>(*pObj);
632     const uno::Reference< awt::XControlModel >&  xControlModel =
633             rFormObj.GetUnoControlModel();
634 
635     OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
636     if( !xControlModel.is() )
637         return nullptr;
638 
639     uno::Reference< beans::XPropertySet >  xPropSet( xControlModel, uno::UNO_QUERY );
640 
641     OUString sPropName("ClassId");
642     if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
643         return nullptr;
644 
645     uno::Any aTmp = xPropSet->getPropertyValue( sPropName );
646     if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
647     {
648         if( lcl_html_isHTMLControl( *n ) )
649         {
650             return pObj;
651         }
652     }
653 
654     return nullptr;
655 }
656 
GetControlSize(const SdrUnoObj & rFormObj,Size & rSz,SwDoc * pDoc)657 static void GetControlSize(const SdrUnoObj& rFormObj, Size& rSz, SwDoc *pDoc)
658 {
659     SwViewShell *pVSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
660     if( !pVSh )
661         return;
662 
663     uno::Reference< awt::XControl >  xControl;
664     SdrView* pDrawView = pVSh->GetDrawView();
665     OSL_ENSURE( pDrawView && pVSh->GetWin(), "no DrawView or window!" );
666     if ( pDrawView && pVSh->GetWin() )
667         xControl = rFormObj.GetUnoControl( *pDrawView, *pVSh->GetWin()->GetOutDev() );
668     uno::Reference< awt::XTextLayoutConstrains > xLC( xControl, uno::UNO_QUERY );
669     OSL_ENSURE( xLC.is(), "no XTextLayoutConstrains" );
670     if( !xLC.is() )
671         return;
672 
673     sal_Int16 nCols=0, nLines=0;
674     xLC->getColumnsAndLines( nCols, nLines );
675     rSz.setWidth( nCols );
676     rSz.setHeight( nLines );
677 }
678 
OutHTML_DrawFrameFormatAsControl(Writer & rWrt,const SwDrawFrameFormat & rFormat,const SdrUnoObj & rFormObj,bool bInCntnr)679 Writer& OutHTML_DrawFrameFormatAsControl( Writer& rWrt,
680                                      const SwDrawFrameFormat& rFormat,
681                                      const SdrUnoObj& rFormObj,
682                                      bool bInCntnr )
683 {
684     const uno::Reference< awt::XControlModel >& xControlModel =
685         rFormObj.GetUnoControlModel();
686 
687     OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
688     if( !xControlModel.is() )
689         return rWrt;
690 
691     uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
692     uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
693             xPropSet->getPropertySetInfo();
694 
695     SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
696     rHTMLWrt.m_nFormCntrlCnt++;
697 
698     enum Tag { TAG_INPUT, TAG_SELECT, TAG_TEXTAREA, TAG_NONE };
699     static char const * const TagNames[] = {
700         OOO_STRING_SVTOOLS_HTML_input, OOO_STRING_SVTOOLS_HTML_select,
701         OOO_STRING_SVTOOLS_HTML_textarea };
702     Tag eTag = TAG_INPUT;
703     enum Type {
704         TYPE_TEXT, TYPE_PASSWORD, TYPE_CHECKBOX, TYPE_RADIO, TYPE_FILE,
705         TYPE_SUBMIT, TYPE_IMAGE, TYPE_RESET, TYPE_BUTTON, TYPE_NONE };
706     static char const * const TypeNames[] = {
707         OOO_STRING_SVTOOLS_HTML_IT_text, OOO_STRING_SVTOOLS_HTML_IT_password,
708         OOO_STRING_SVTOOLS_HTML_IT_checkbox, OOO_STRING_SVTOOLS_HTML_IT_radio,
709         OOO_STRING_SVTOOLS_HTML_IT_file, OOO_STRING_SVTOOLS_HTML_IT_submit,
710         OOO_STRING_SVTOOLS_HTML_IT_image, OOO_STRING_SVTOOLS_HTML_IT_reset,
711         OOO_STRING_SVTOOLS_HTML_IT_button };
712     Type eType = TYPE_NONE;
713     OUString sValue;
714     OString sOptions;
715     bool bEmptyValue = false;
716     uno::Any aTmp = xPropSet->getPropertyValue( "ClassId" );
717     sal_Int16 nClassId = *o3tl::doAccess<sal_Int16>(aTmp);
718     HtmlFrmOpts nFrameOpts = HTML_FRMOPTS_CONTROL;
719     switch( nClassId )
720     {
721     case form::FormComponentType::CHECKBOX:
722     case form::FormComponentType::RADIOBUTTON:
723         eType = (form::FormComponentType::CHECKBOX == nClassId
724                     ? TYPE_CHECKBOX : TYPE_RADIO);
725         aTmp = xPropSet->getPropertyValue( "DefaultState" );
726         if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
727         {
728             if ( TRISTATE_FALSE != *n )
729             {
730                 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_checked "=\""
731                     OOO_STRING_SVTOOLS_HTML_O_checked
732                     "\"";
733             }
734         }
735 
736         aTmp = xPropSet->getPropertyValue( "RefValue" );
737         if( auto rVal = o3tl::tryAccess<OUString>(aTmp) )
738 
739         {
740             if( rVal->isEmpty() )
741                 bEmptyValue = true;
742             else if( *rVal != OOO_STRING_SVTOOLS_HTML_on )
743                 sValue = *rVal;
744         }
745         break;
746 
747     case form::FormComponentType::COMMANDBUTTON:
748         {
749             form::FormButtonType eButtonType = form::FormButtonType_PUSH;
750             aTmp = xPropSet->getPropertyValue( "ButtonType" );
751             if( auto t = o3tl::tryAccess<form::FormButtonType>(aTmp) )
752                 eButtonType = *t;
753 
754             switch( eButtonType )
755             {
756             case form::FormButtonType_RESET:
757                 eType = TYPE_RESET;
758                 break;
759             case form::FormButtonType_SUBMIT:
760                 eType = TYPE_SUBMIT;
761                 break;
762             case form::FormButtonType_PUSH:
763             default:
764                 eType = TYPE_BUTTON;
765             }
766 
767             aTmp = xPropSet->getPropertyValue( "Label" );
768             if( auto s = o3tl::tryAccess<OUString>(aTmp) )
769             {
770                 if( !s->isEmpty() )
771                 {
772                     sValue = *s;
773                 }
774             }
775         }
776         break;
777 
778     case form::FormComponentType::LISTBOX:
779         if( rHTMLWrt.m_bLFPossible )
780             rHTMLWrt.OutNewLine( true );
781         eTag = TAG_SELECT;
782         aTmp = xPropSet->getPropertyValue( "Dropdown" );
783         if( auto b1 = o3tl::tryAccess<bool>(aTmp) )
784         {
785             if( !*b1 )
786             {
787                 Size aSz( 0, 0 );
788                 GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
789 
790                 // How many are visible ??
791                 if( aSz.Height() )
792                 {
793                     sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
794                         OString::number(static_cast<sal_Int32>(aSz.Height())) + "\"";
795                 }
796 
797                 auto aTmp2 = xPropSet->getPropertyValue( "MultiSelection" );
798                 if( auto b2 = o3tl::tryAccess<bool>(aTmp2) )
799                 {
800                     if ( *b2 )
801                     {
802                         sOptions += " " OOO_STRING_SVTOOLS_HTML_O_multiple;
803                     }
804                 }
805             }
806         }
807         break;
808 
809     case form::FormComponentType::TEXTFIELD:
810         {
811             Size aSz( 0, 0 );
812             GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
813 
814             bool bMultiLine = false;
815             OUString sMultiLine("MultiLine");
816             if( xPropSetInfo->hasPropertyByName( sMultiLine ) )
817             {
818                 aTmp = xPropSet->getPropertyValue( sMultiLine );
819                 auto b = o3tl::tryAccess<bool>(aTmp);
820                 bMultiLine = b && *b;
821             }
822 
823             if( bMultiLine )
824             {
825                 if( rHTMLWrt.m_bLFPossible )
826                     rHTMLWrt.OutNewLine( true );
827                 eTag = TAG_TEXTAREA;
828 
829                 if( aSz.Height() )
830                 {
831                     sOptions += " " OOO_STRING_SVTOOLS_HTML_O_rows "=\"" +
832                         OString::number(static_cast<sal_Int32>(aSz.Height())) + "\"";
833                 }
834                 if( aSz.Width() )
835                 {
836                     sOptions += " " OOO_STRING_SVTOOLS_HTML_O_cols "=\"" +
837                         OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
838                 }
839 
840                 aTmp = xPropSet->getPropertyValue( "HScroll" );
841                 if( aTmp.getValueType() == cppu::UnoType<void>::get() ||
842                     (aTmp.getValueType() == cppu::UnoType<bool>::get() &&
843                     !*o3tl::forceAccess<bool>(aTmp)) )
844                 {
845                     const char *pWrapStr = nullptr;
846                     auto aTmp2 = xPropSet->getPropertyValue( "HardLineBreaks" );
847                     auto b = o3tl::tryAccess<bool>(aTmp2);
848                     pWrapStr = (b && *b) ? OOO_STRING_SVTOOLS_HTML_WW_hard
849                                          : OOO_STRING_SVTOOLS_HTML_WW_soft;
850                     sOptions += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_wrap "=\"") +
851                         pWrapStr + "\"";
852                 }
853             }
854             else
855             {
856                 eType = TYPE_TEXT;
857                 OUString sEchoChar("EchoChar");
858                 if( xPropSetInfo->hasPropertyByName( sEchoChar ) )
859                 {
860                     aTmp = xPropSet->getPropertyValue( sEchoChar );
861                     if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
862                     {
863                         if( *n != 0 )
864                             eType = TYPE_PASSWORD;
865                     }
866                 }
867 
868                 if( aSz.Width() )
869                 {
870                     sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
871                         OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
872                 }
873 
874                 aTmp = xPropSet->getPropertyValue( "MaxTextLen" );
875                 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
876                 {
877                     if( *n != 0 )
878                     {
879                         sOptions += " " OOO_STRING_SVTOOLS_HTML_O_maxlength "=\"" +
880                             OString::number(static_cast<sal_Int32>(*n)) + "\"";
881                     }
882                 }
883 
884                 if( xPropSetInfo->hasPropertyByName( "DefaultText" ) )
885                 {
886                     aTmp = xPropSet->getPropertyValue( "DefaultText" );
887                     if( auto s = o3tl::tryAccess<OUString>(aTmp) )
888                     {
889                         if( !s->isEmpty() )
890                         {
891                             sValue = *s;
892                         }
893                     }
894                 }
895             }
896         }
897         break;
898 
899     case form::FormComponentType::FILECONTROL:
900         {
901             Size aSz( 0, 0 );
902             GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
903             eType = TYPE_FILE;
904 
905             if( aSz.Width() )
906             {
907                 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
908                     OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
909             }
910 
911             // VALUE vim form: don't export because of security reasons
912         }
913         break;
914 
915     case form::FormComponentType::IMAGEBUTTON:
916         eType = TYPE_IMAGE;
917         nFrameOpts = HTML_FRMOPTS_IMG_CONTROL;
918         break;
919 
920     default:                // doesn't know HTML
921         eTag = TAG_NONE;    // therefore skip it
922         break;
923     }
924 
925     if( eTag == TAG_NONE )
926         return rWrt;
927 
928     OString sOut = OString::Concat("<") + TagNames[eTag];
929     if( eType != TYPE_NONE )
930     {
931         sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_type "=\"") +
932             TypeNames[eType] + "\"";
933     }
934 
935     aTmp = xPropSet->getPropertyValue("Name");
936     if( auto s = o3tl::tryAccess<OUString>(aTmp) )
937     {
938         if( !s->isEmpty() )
939         {
940             sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
941             rWrt.Strm().WriteOString( sOut );
942             HTMLOutFuncs::Out_String( rWrt.Strm(), *s,
943                                       rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
944             sOut = "\"";
945         }
946     }
947 
948     aTmp = xPropSet->getPropertyValue("Enabled");
949     if( auto b = o3tl::tryAccess<bool>(aTmp) )
950     {
951         if( !*b )
952         {
953             sOut += " " OOO_STRING_SVTOOLS_HTML_O_disabled;
954         }
955     }
956 
957     if( !sValue.isEmpty() || bEmptyValue )
958     {
959         sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
960         rWrt.Strm().WriteOString( sOut );
961         HTMLOutFuncs::Out_String( rWrt.Strm(), sValue, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
962         sOut = "\"";
963     }
964 
965     sOut += " " + sOptions;
966 
967     if( TYPE_IMAGE == eType )
968     {
969         aTmp = xPropSet->getPropertyValue( "ImageURL" );
970         if( auto s = o3tl::tryAccess<OUString>(aTmp) )
971         {
972             if( !s->isEmpty() )
973             {
974                 sOut += " " OOO_STRING_SVTOOLS_HTML_O_src "=\"";
975                 rWrt.Strm().WriteOString( sOut );
976 
977                 HTMLOutFuncs::Out_String( rWrt.Strm(),
978                             URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), *s),
979                             rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
980                 sOut = "\"";
981             }
982         }
983 
984         Size aTwipSz( rFormObj.GetLogicRect().GetSize() );
985         Size aPixelSz( 0, 0 );
986         if( (aTwipSz.Width() || aTwipSz.Height()) &&
987             Application::GetDefaultDevice() )
988         {
989             aPixelSz =
990                 Application::GetDefaultDevice()->LogicToPixel( aTwipSz,
991                                                     MapMode(MapUnit::MapTwip) );
992             if( !aPixelSz.Width() && aTwipSz.Width() )
993                 aPixelSz.setWidth( 1 );
994             if( !aPixelSz.Height() && aTwipSz.Height() )
995                 aPixelSz.setHeight( 1 );
996         }
997 
998         if( aPixelSz.Width() )
999         {
1000             sOut += " " OOO_STRING_SVTOOLS_HTML_O_width "=\"" +
1001                 OString::number(static_cast<sal_Int32>(aPixelSz.Width())) + "\"";
1002         }
1003 
1004         if( aPixelSz.Height() )
1005         {
1006             sOut += " " OOO_STRING_SVTOOLS_HTML_O_height "=\"" +
1007                 OString::number(static_cast<sal_Int32>(aPixelSz.Height())) + "\"";
1008         }
1009     }
1010 
1011     aTmp = xPropSet->getPropertyValue( "TabIndex" );
1012     if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1013     {
1014         sal_Int16 nTabIndex = *n;
1015         if( nTabIndex > 0 )
1016         {
1017             if( nTabIndex >= 32767 )
1018                 nTabIndex = 32767;
1019 
1020             sOut += " " OOO_STRING_SVTOOLS_HTML_O_tabindex "=\"" +
1021                 OString::number(static_cast<sal_Int32>(nTabIndex)) + "\"";
1022         }
1023     }
1024 
1025     if( !sOut.isEmpty() )
1026         rWrt.Strm().WriteOString( sOut );
1027 
1028     OSL_ENSURE( !bInCntnr, "Container is not supported for Controls" );
1029     if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) && !bInCntnr )
1030     {
1031         // If Character-Objects can't be positioned absolutely,
1032         // then delete the corresponding flag.
1033         nFrameOpts |= (TYPE_IMAGE == eType
1034                             ? HTML_FRMOPTS_IMG_CONTROL_CSS1
1035                             : HTML_FRMOPTS_CONTROL_CSS1);
1036     }
1037     OString aEndTags;
1038     if( nFrameOpts != HtmlFrmOpts::NONE )
1039         aEndTags = rHTMLWrt.OutFrameFormatOptions(rFormat, OUString(), nFrameOpts);
1040 
1041     if( rHTMLWrt.m_bCfgOutStyles )
1042     {
1043         bool bEdit = TAG_TEXTAREA == eTag || TYPE_FILE == eType ||
1044                      TYPE_TEXT == eType;
1045 
1046         SfxItemSet aItemSet( rHTMLWrt.m_pDoc->GetAttrPool(), svl::Items<RES_CHRATR_BEGIN,
1047                              RES_CHRATR_END>{} );
1048         if( xPropSetInfo->hasPropertyByName( "BackgroundColor" ) )
1049         {
1050             aTmp = xPropSet->getPropertyValue( "BackgroundColor" );
1051             if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) )
1052             {
1053                 Color aCol(ColorTransparency, *n);
1054                 aItemSet.Put( SvxBrushItem( aCol, RES_CHRATR_BACKGROUND ) );
1055             }
1056         }
1057         if( xPropSetInfo->hasPropertyByName( "TextColor" ) )
1058         {
1059             aTmp = xPropSet->getPropertyValue( "TextColor" );
1060             if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) )
1061             {
1062                 Color aColor( ColorTransparency, *n );
1063                 aItemSet.Put( SvxColorItem( aColor, RES_CHRATR_COLOR ) );
1064             }
1065         }
1066         if( xPropSetInfo->hasPropertyByName( "FontHeight" ) )
1067         {
1068             aTmp = xPropSet->getPropertyValue( "FontHeight" );
1069             if( auto nHeight = o3tl::tryAccess<float>(aTmp) )
1070 
1071             {
1072                 if( *nHeight > 0  && (!bEdit || !rtl::math::approxEqual(*nHeight, 10.0)) )
1073                     aItemSet.Put( SvxFontHeightItem( sal_Int16(*nHeight * 20.), 100, RES_CHRATR_FONTSIZE ) );
1074             }
1075         }
1076         if( xPropSetInfo->hasPropertyByName( "FontName" ) )
1077         {
1078             aTmp = xPropSet->getPropertyValue( "FontName" );
1079             if( auto aFName = o3tl::tryAccess<OUString>(aTmp) )
1080             {
1081                 if( !aFName->isEmpty() )
1082                 {
1083                     vcl::Font aFixedFont( OutputDevice::GetDefaultFont(
1084                                         DefaultFontType::FIXED, LANGUAGE_ENGLISH_US,
1085                                         GetDefaultFontFlags::OnlyOne ) );
1086                     if( !bEdit || *aFName != aFixedFont.GetFamilyName() )
1087                     {
1088                         FontFamily eFamily = FAMILY_DONTKNOW;
1089                         if( xPropSetInfo->hasPropertyByName( "FontFamily" ) )
1090                         {
1091                             auto aTmp2 = xPropSet->getPropertyValue( "FontFamily" );
1092                             if( auto n = o3tl::tryAccess<sal_Int16>(aTmp2) )
1093                                 eFamily = static_cast<FontFamily>(*n);
1094                         }
1095                         SvxFontItem aItem(eFamily, *aFName, OUString(), PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT);
1096                         aItemSet.Put( aItem );
1097                     }
1098                 }
1099             }
1100         }
1101         if( xPropSetInfo->hasPropertyByName( "FontWeight" ) )
1102         {
1103             aTmp = xPropSet->getPropertyValue( "FontWeight" );
1104             if( auto x = o3tl::tryAccess<float>(aTmp) )
1105             {
1106                 FontWeight eWeight =
1107                     vcl::unohelper::ConvertFontWeight( *x );
1108                 if( eWeight != WEIGHT_DONTKNOW && eWeight != WEIGHT_NORMAL )
1109                     aItemSet.Put( SvxWeightItem( eWeight, RES_CHRATR_WEIGHT ) );
1110             }
1111         }
1112         if( xPropSetInfo->hasPropertyByName( "FontSlant" ) )
1113         {
1114             aTmp = xPropSet->getPropertyValue( "FontSlant" );
1115             if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1116             {
1117                 FontItalic eItalic = static_cast<FontItalic>(*n);
1118                 if( eItalic != ITALIC_DONTKNOW && eItalic != ITALIC_NONE )
1119                     aItemSet.Put( SvxPostureItem( eItalic, RES_CHRATR_POSTURE ) );
1120             }
1121         }
1122         if( xPropSetInfo->hasPropertyByName( "FontLineStyle" ) )
1123         {
1124             aTmp = xPropSet->getPropertyValue( "FontLineStyle" );
1125             if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1126             {
1127                 FontLineStyle eUnderline = static_cast<FontLineStyle>(*n);
1128                 if( eUnderline != LINESTYLE_DONTKNOW  &&
1129                     eUnderline != LINESTYLE_NONE )
1130                     aItemSet.Put( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ) );
1131             }
1132         }
1133         if( xPropSetInfo->hasPropertyByName( "FontStrikeout" ) )
1134         {
1135             aTmp = xPropSet->getPropertyValue( "FontStrikeout" );
1136             if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1137             {
1138                 FontStrikeout eStrikeout = static_cast<FontStrikeout>(*n);
1139                 if( eStrikeout != STRIKEOUT_DONTKNOW &&
1140                     eStrikeout != STRIKEOUT_NONE )
1141                     aItemSet.Put( SvxCrossedOutItem( eStrikeout, RES_CHRATR_CROSSEDOUT ) );
1142             }
1143         }
1144 
1145         rHTMLWrt.OutCSS1_FrameFormatOptions( rFormat, nFrameOpts, &rFormObj,
1146                                         &aItemSet );
1147     }
1148 
1149     uno::Reference< form::XFormComponent >  xFormComp( xControlModel, uno::UNO_QUERY );
1150     lcl_html_outEvents( rWrt.Strm(), xFormComp, rHTMLWrt.m_bCfgStarBasic,
1151                         rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1152 
1153     rWrt.Strm().WriteChar( '>' );
1154 
1155     if( TAG_SELECT == eTag )
1156     {
1157         aTmp = xPropSet->getPropertyValue( "StringItemList" );
1158         if( auto aList = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp) )
1159         {
1160             rHTMLWrt.IncIndentLevel(); // the content of Select can be indented
1161             sal_Int32 nCnt = aList->getLength();
1162             const OUString *pStrings = aList->getConstArray();
1163 
1164             const OUString *pValues = nullptr;
1165             sal_Int32 nValCnt = 0;
1166             auto aTmp2 = xPropSet->getPropertyValue( "ListSource" );
1167             uno::Sequence<OUString> aValList;
1168             if( auto s = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp2) )
1169             {
1170                 aValList = *s;
1171                 nValCnt = aValList.getLength();
1172                 pValues = aValList.getConstArray();
1173             }
1174 
1175             uno::Any aSelTmp = xPropSet->getPropertyValue( "DefaultSelection" );
1176             const sal_Int16 *pSels = nullptr;
1177             sal_Int32 nSel = 0;
1178             sal_Int32 nSelCnt = 0;
1179             uno::Sequence<sal_Int16> aSelList;
1180             if( auto s = o3tl::tryAccess<uno::Sequence<sal_Int16>>(aSelTmp) )
1181             {
1182                 aSelList = *s;
1183                 nSelCnt = aSelList.getLength();
1184                 pSels = aSelList.getConstArray();
1185             }
1186 
1187             for( sal_Int32 i = 0; i < nCnt; i++ )
1188             {
1189                 OUString sVal;
1190                 bool bSelected = false, bEmptyVal = false;
1191                 if( i < nValCnt )
1192                 {
1193                     const OUString& rVal = pValues[i];
1194                     if( rVal == "$$$empty$$$" )
1195                         bEmptyVal = true;
1196                     else
1197                         sVal = rVal;
1198                 }
1199 
1200                 bSelected = (nSel < nSelCnt) && pSels[nSel] == i;
1201                 if( bSelected )
1202                     nSel++;
1203 
1204                 rHTMLWrt.OutNewLine(); // every Option gets its own line
1205                 sOut = "<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option;
1206                 if( !sVal.isEmpty() || bEmptyVal )
1207                 {
1208                     sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
1209                     rWrt.Strm().WriteOString( sOut );
1210                     HTMLOutFuncs::Out_String( rWrt.Strm(), sVal,
1211                         rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1212                     sOut = "\"";
1213                 }
1214                 if( bSelected )
1215                     sOut += " " OOO_STRING_SVTOOLS_HTML_O_selected;
1216 
1217                 sOut += ">";
1218                 rWrt.Strm().WriteOString( sOut );
1219 
1220                 HTMLOutFuncs::Out_String( rWrt.Strm(), pStrings[i],
1221                                           rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1222             }
1223             HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option), false );
1224 
1225             rHTMLWrt.DecIndentLevel();
1226             rHTMLWrt.OutNewLine();// the </SELECT> gets its own line
1227         }
1228         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_select), false );
1229     }
1230     else if( TAG_TEXTAREA == eTag )
1231     {
1232         // In TextAreas no additional spaces or LF may be exported!
1233         OUString sVal;
1234         aTmp = xPropSet->getPropertyValue( "DefaultText" );
1235         if( auto s = o3tl::tryAccess<OUString>(aTmp) )
1236         {
1237             if( !s->isEmpty() )
1238             {
1239                 sVal = *s;
1240             }
1241         }
1242         if( !sVal.isEmpty() )
1243         {
1244             sVal = convertLineEnd(sVal, LINEEND_LF);
1245             sal_Int32 nPos = 0;
1246             while ( nPos != -1 )
1247             {
1248                 if( nPos )
1249                     rWrt.Strm().WriteCharPtr( SAL_NEWLINE_STRING );
1250                 OUString aLine = sVal.getToken( 0, 0x0A, nPos );
1251                 HTMLOutFuncs::Out_String( rWrt.Strm(), aLine,
1252                                         rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1253             }
1254         }
1255         HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_textarea), false );
1256     }
1257     else if( TYPE_CHECKBOX == eType || TYPE_RADIO == eType )
1258     {
1259         aTmp = xPropSet->getPropertyValue("Label");
1260         if( auto s = o3tl::tryAccess<OUString>(aTmp) )
1261         {
1262             if( !s->isEmpty() )
1263             {
1264                 HTMLOutFuncs::Out_String( rWrt.Strm(), *s,
1265                     rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters ).WriteChar( ' ' );
1266             }
1267         }
1268     }
1269 
1270     if( !aEndTags.isEmpty() )
1271         rWrt.Strm().WriteOString( aEndTags );
1272 
1273     // Controls aren't bound to a paragraph, therefore don't output LF anymore!
1274     rHTMLWrt.m_bLFPossible = false;
1275 
1276     if( rHTMLWrt.mxFormComps.is() )
1277         rHTMLWrt.OutHiddenControls( rHTMLWrt.mxFormComps, xPropSet );
1278     return rWrt;
1279 }
1280 
1281 /**
1282  * Find out if a format belongs to a control and if yes return its form.
1283  */
AddControl(HTMLControls & rControls,const SdrUnoObj & rFormObj,sal_uInt32 nNodeIdx)1284 static void AddControl( HTMLControls& rControls,
1285                         const SdrUnoObj& rFormObj,
1286                         sal_uInt32 nNodeIdx )
1287 {
1288     const uno::Reference< awt::XControlModel >& xControlModel =
1289             rFormObj.GetUnoControlModel();
1290     if( !xControlModel.is() )
1291         return;
1292 
1293     uno::Reference< form::XFormComponent >  xFormComp( xControlModel, uno::UNO_QUERY );
1294     uno::Reference< uno::XInterface >  xIfc = xFormComp->getParent();
1295     uno::Reference< form::XForm >  xForm(xIfc, uno::UNO_QUERY);
1296 
1297     OSL_ENSURE( xForm.is(), "Where is the form?" );
1298     if( xForm.is() )
1299     {
1300         uno::Reference< container::XIndexContainer >  xFormComps( xForm, uno::UNO_QUERY );
1301         std::unique_ptr<HTMLControl> pHCntrl(new HTMLControl( xFormComps, nNodeIdx ));
1302         auto itPair = rControls.insert( std::move(pHCntrl) );
1303         if (!itPair.second )
1304         {
1305             if( (*itPair.first)->xFormComps==xFormComps )
1306                 (*itPair.first)->nCount++;
1307         }
1308     }
1309 }
1310 
GetControls()1311 void SwHTMLWriter::GetControls()
1312 {
1313     // Idea: first off collect the paragraph- and character-bound controls.
1314     // In the process for every control the paragraph position and VCForm are
1315     // saved in an array.
1316     // With that array it's possible to find out where form::Forms must be
1317     // opened and closed.
1318 
1319     if( m_pHTMLPosFlyFrames )
1320     {
1321         // collect the paragraph-bound controls
1322         for( size_t i=0; i<m_pHTMLPosFlyFrames->size(); i++ )
1323         {
1324             const SwHTMLPosFlyFrame* pPosFlyFrame = (*m_pHTMLPosFlyFrames)[ i ].get();
1325             if( HtmlOut::Control != pPosFlyFrame->GetOutFn() )
1326                 continue;
1327 
1328             const SdrObject *pSdrObj = pPosFlyFrame->GetSdrObject();
1329             OSL_ENSURE( pSdrObj, "Where is the SdrObject?" );
1330             if( !pSdrObj )
1331                 continue;
1332 
1333             AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj),
1334                         pPosFlyFrame->GetNdIndex().GetIndex() );
1335         }
1336     }
1337 
1338     // and now the ones in a character-bound frame
1339     const SwFrameFormats* pSpzFrameFormats = m_pDoc->GetSpzFrameFormats();
1340     for( size_t i=0; i<pSpzFrameFormats->size(); i++ )
1341     {
1342         const SwFrameFormat *pFrameFormat = (*pSpzFrameFormats)[i];
1343         if( RES_DRAWFRMFMT != pFrameFormat->Which() )
1344             continue;
1345 
1346         const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1347         const SwPosition *pPos = rAnchor.GetContentAnchor();
1348         if ((RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) || !pPos)
1349             continue;
1350 
1351         const SdrObject *pSdrObj =
1352             SwHTMLWriter::GetHTMLControl( *static_cast<const SwDrawFrameFormat*>(pFrameFormat) );
1353         if( !pSdrObj )
1354             continue;
1355 
1356         AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj), pPos->nNode.GetIndex() );
1357     }
1358 }
1359 
HTMLControl(const uno::Reference<container::XIndexContainer> & rFormComps,sal_uInt32 nIdx)1360 HTMLControl::HTMLControl(
1361         const uno::Reference< container::XIndexContainer > & rFormComps,
1362         sal_uInt32 nIdx ) :
1363     xFormComps( rFormComps ), nNdIdx( nIdx ), nCount( 1 )
1364 {}
1365 
~HTMLControl()1366 HTMLControl::~HTMLControl()
1367 {}
1368 
1369 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1370