Line data Source code
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 :
21 : #include "node.hxx"
22 : #include "rect.hxx"
23 : #include "symbol.hxx"
24 : #include "smmod.hxx"
25 : #include "document.hxx"
26 : #include "view.hxx"
27 : #include "mathtype.hxx"
28 : #include "tmpdevice.hxx"
29 : #include "visitors.hxx"
30 :
31 : #include <comphelper/string.hxx>
32 : #include <tools/color.hxx>
33 : #include <tools/fract.hxx>
34 : #include <tools/gen.hxx>
35 : #include <vcl/outdev.hxx>
36 :
37 : #include <math.h>
38 : #include <float.h>
39 : #include <vector>
40 :
41 15756 : SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken)
42 : : aNodeToken( rNodeToken )
43 : , eType( eNodeType )
44 : , eScaleMode( SCALE_NONE )
45 : , eRectHorAlign( RHA_LEFT )
46 : , nFlags( 0 )
47 : , nAttributes( 0 )
48 : , bIsPhantom( false )
49 : , bIsSelected( false )
50 : , nAccIndex( -1 )
51 15756 : , aParentNode( NULL )
52 : {
53 15756 : }
54 :
55 :
56 15735 : SmNode::~SmNode()
57 : {
58 15735 : }
59 :
60 :
61 0 : bool SmNode::IsVisible() const
62 : {
63 0 : return false;
64 : }
65 :
66 :
67 0 : sal_uInt16 SmNode::GetNumSubNodes() const
68 : {
69 0 : return 0;
70 : }
71 :
72 :
73 0 : SmNode * SmNode::GetSubNode(sal_uInt16 /*nIndex*/)
74 : {
75 0 : return NULL;
76 : }
77 :
78 :
79 5865 : SmNode * SmNode::GetLeftMost()
80 : // returns leftmost node of current subtree.
81 : //! (this assumes the one with index 0 is always the leftmost subnode
82 : //! for the current node).
83 : {
84 5865 : SmNode *pNode = GetNumSubNodes() > 0 ?
85 5865 : GetSubNode(0) : NULL;
86 :
87 5865 : return pNode ? pNode->GetLeftMost() : this;
88 : }
89 :
90 :
91 0 : void SmNode::SetPhantom(bool bIsPhantomP)
92 : {
93 0 : if (! (Flags() & FLG_VISIBLE))
94 0 : bIsPhantom = bIsPhantomP;
95 :
96 : SmNode *pNode;
97 0 : sal_uInt16 nSize = GetNumSubNodes();
98 0 : for (sal_uInt16 i = 0; i < nSize; i++)
99 0 : if (NULL != (pNode = GetSubNode(i)))
100 0 : pNode->SetPhantom(bIsPhantom);
101 0 : }
102 :
103 :
104 0 : void SmNode::SetColor(const Color& rColor)
105 : {
106 0 : if (! (Flags() & FLG_COLOR))
107 0 : GetFont().SetColor(rColor);
108 :
109 : SmNode *pNode;
110 0 : sal_uInt16 nSize = GetNumSubNodes();
111 0 : for (sal_uInt16 i = 0; i < nSize; i++)
112 0 : if (NULL != (pNode = GetSubNode(i)))
113 0 : pNode->SetColor(rColor);
114 0 : }
115 :
116 :
117 49 : void SmNode::SetAttribut(sal_uInt16 nAttrib)
118 : {
119 49 : if (
120 98 : (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
121 49 : (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
122 : )
123 : {
124 49 : nAttributes |= nAttrib;
125 : }
126 :
127 : SmNode *pNode;
128 49 : sal_uInt16 nSize = GetNumSubNodes();
129 97 : for (sal_uInt16 i = 0; i < nSize; i++)
130 48 : if (NULL != (pNode = GetSubNode(i)))
131 24 : pNode->SetAttribut(nAttrib);
132 49 : }
133 :
134 :
135 0 : void SmNode::ClearAttribut(sal_uInt16 nAttrib)
136 : {
137 0 : if (
138 0 : (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
139 0 : (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
140 : )
141 : {
142 0 : nAttributes &= ~nAttrib;
143 : }
144 :
145 : SmNode *pNode;
146 0 : sal_uInt16 nSize = GetNumSubNodes();
147 0 : for (sal_uInt16 i = 0; i < nSize; i++)
148 0 : if (NULL != (pNode = GetSubNode(i)))
149 0 : pNode->ClearAttribut(nAttrib);
150 0 : }
151 :
152 :
153 12 : void SmNode::SetFont(const SmFace &rFace)
154 : {
155 12 : if (!(Flags() & FLG_FONT))
156 12 : GetFont() = rFace;
157 :
158 : SmNode *pNode;
159 12 : sal_uInt16 nSize = GetNumSubNodes();
160 24 : for (sal_uInt16 i = 0; i < nSize; i++)
161 12 : if (NULL != (pNode = GetSubNode(i)))
162 6 : pNode->SetFont(rFace);
163 12 : }
164 :
165 :
166 228 : void SmNode::SetFontSize(const Fraction &rSize, FontSizeType nType)
167 : //! 'rSize' is in units of pts
168 : {
169 228 : Size aFntSize;
170 :
171 228 : if (!(Flags() & FLG_SIZE))
172 : {
173 : Fraction aVal (SmPtsTo100th_mm(rSize.GetNumerator()),
174 228 : rSize.GetDenominator());
175 228 : long nHeight = (long)aVal;
176 :
177 228 : aFntSize = GetFont().GetSize();
178 228 : aFntSize.Width() = 0;
179 228 : switch(nType)
180 : {
181 : case FontSizeType::ABSOLUT:
182 228 : aFntSize.Height() = nHeight;
183 228 : break;
184 :
185 : case FontSizeType::PLUS:
186 0 : aFntSize.Height() += nHeight;
187 0 : break;
188 :
189 : case FontSizeType::MINUS:
190 0 : aFntSize.Height() -= nHeight;
191 0 : break;
192 :
193 : case FontSizeType::MULTIPLY:
194 0 : aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize);
195 0 : break;
196 :
197 : case FontSizeType::DIVIDE:
198 0 : if (rSize != Fraction(0L))
199 0 : aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize);
200 0 : break;
201 : default:
202 0 : break;
203 : }
204 :
205 : // check the requested size against maximum value
206 228 : static int const nMaxVal = SmPtsTo100th_mm(128);
207 228 : if (aFntSize.Height() > nMaxVal)
208 0 : aFntSize.Height() = nMaxVal;
209 :
210 228 : GetFont().SetSize(aFntSize);
211 : }
212 :
213 : SmNode *pNode;
214 228 : sal_uInt16 nSize = GetNumSubNodes();
215 576 : for (sal_uInt16 i = 0; i < nSize; i++)
216 348 : if (NULL != (pNode = GetSubNode(i)))
217 162 : pNode->SetFontSize(rSize, nType);
218 228 : }
219 :
220 :
221 3846 : void SmNode::SetSize(const Fraction &rSize)
222 : {
223 3846 : GetFont() *= rSize;
224 :
225 : SmNode *pNode;
226 3846 : sal_uInt16 nSize = GetNumSubNodes();
227 5285 : for (sal_uInt16 i = 0; i < nSize; i++)
228 1439 : if (NULL != (pNode = GetSubNode(i)))
229 1317 : pNode->SetSize(rSize);
230 3846 : }
231 :
232 :
233 996 : void SmNode::SetRectHorAlign(RectHorAlign eHorAlign, bool bApplyToSubTree )
234 : {
235 996 : if (!(Flags() & FLG_HORALIGN))
236 996 : eRectHorAlign = eHorAlign;
237 :
238 996 : if (bApplyToSubTree)
239 : {
240 : SmNode *pNode;
241 102 : sal_uInt16 nSize = GetNumSubNodes();
242 102 : for (sal_uInt16 i = 0; i < nSize; i++)
243 0 : if (NULL != (pNode = GetSubNode(i)))
244 0 : pNode->SetRectHorAlign(eHorAlign);
245 : }
246 996 : }
247 :
248 :
249 7354 : void SmNode::PrepareAttributes()
250 : {
251 7354 : GetFont().SetWeight((Attributes() & ATTR_BOLD) ? WEIGHT_BOLD : WEIGHT_NORMAL);
252 7354 : GetFont().SetItalic((Attributes() & ATTR_ITALIC) ? ITALIC_NORMAL : ITALIC_NONE);
253 7354 : }
254 :
255 :
256 16185 : void SmNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
257 : {
258 16185 : bIsPhantom = false;
259 16185 : nFlags = 0;
260 16185 : nAttributes = 0;
261 :
262 16185 : switch (rFormat.GetHorAlign())
263 0 : { case AlignLeft: eRectHorAlign = RHA_LEFT; break;
264 16020 : case AlignCenter: eRectHorAlign = RHA_CENTER; break;
265 165 : case AlignRight: eRectHorAlign = RHA_RIGHT; break;
266 : }
267 :
268 16185 : GetFont() = rFormat.GetFont(FNT_MATH);
269 : OSL_ENSURE( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
270 : "unexpected CharSet" );
271 16185 : GetFont().SetWeight(WEIGHT_NORMAL);
272 16185 : GetFont().SetItalic(ITALIC_NONE);
273 :
274 : SmNode *pNode;
275 16185 : sal_uInt16 nSize = GetNumSubNodes();
276 34236 : for (sal_uInt16 i = 0; i < nSize; i++)
277 18051 : if (NULL != (pNode = GetSubNode(i)))
278 14219 : pNode->Prepare(rFormat, rDocShell);
279 16185 : }
280 :
281 0 : sal_uInt16 SmNode::FindIndex() const
282 : {
283 0 : const SmStructureNode* pParent = GetParent();
284 0 : if (!pParent) { return 0; }
285 :
286 0 : for (sal_uInt16 i = 0; i < pParent->GetNumSubNodes(); ++i) {
287 0 : if (pParent->GetSubNode(i) == this) {
288 0 : return i;
289 : }
290 : }
291 :
292 : DBG_ASSERT(false, "Connection between parent and child is inconsistent.");
293 0 : return 0;
294 : }
295 :
296 :
297 30653 : void SmNode::Move(const Point& rPosition)
298 : {
299 30653 : if (rPosition.X() == 0 && rPosition.Y() == 0)
300 30659 : return;
301 :
302 30647 : SmRect::Move(rPosition);
303 :
304 : SmNode *pNode;
305 30647 : sal_uInt16 nSize = GetNumSubNodes();
306 62855 : for (sal_uInt16 i = 0; i < nSize; i++)
307 32208 : if (NULL != (pNode = GetSubNode(i)))
308 22845 : pNode->Move(rPosition);
309 : }
310 :
311 :
312 0 : void SmNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
313 : {
314 : SmNode *pNode;
315 0 : sal_uInt16 nSize = GetNumSubNodes();
316 0 : for (sal_uInt16 i = 0; i < nSize; i++)
317 0 : if (NULL != (pNode = GetSubNode(i)))
318 0 : pNode->Arrange(rDev, rFormat);
319 0 : }
320 :
321 6 : void SmNode::CreateTextFromNode(OUString &rText)
322 : {
323 : SmNode *pNode;
324 6 : sal_uInt16 nSize = GetNumSubNodes();
325 6 : if (nSize > 1)
326 0 : rText += "{";
327 12 : for (sal_uInt16 i = 0; i < nSize; i++)
328 6 : if (NULL != (pNode = GetSubNode(i)))
329 6 : pNode->CreateTextFromNode(rText);
330 6 : if (nSize > 1)
331 : {
332 0 : rText = comphelper::string::stripEnd(rText, ' ');
333 0 : rText += "} ";
334 : }
335 6 : }
336 :
337 :
338 0 : void SmNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong /*nWidth*/)
339 : {
340 0 : }
341 :
342 :
343 0 : void SmNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong /*nHeight*/)
344 : {
345 0 : }
346 :
347 :
348 81 : const SmNode * SmNode::FindTokenAt(sal_uInt16 nRow, sal_uInt16 nCol) const
349 : // returns (first) ** visible ** (sub)node with the tokens text at
350 : // position 'nRow', 'nCol'.
351 : //! (there should be exactly one such node if any)
352 : {
353 162 : if ( IsVisible()
354 8 : && nRow == GetToken().nRow
355 89 : && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.getLength())
356 8 : return this;
357 : else
358 : {
359 73 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
360 105 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
361 57 : { const SmNode *pNode = GetSubNode(i);
362 :
363 57 : if (!pNode)
364 0 : continue;
365 :
366 57 : const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
367 57 : if (pResult)
368 25 : return pResult;
369 : }
370 : }
371 :
372 48 : return 0;
373 : }
374 :
375 :
376 0 : const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
377 : {
378 0 : long nDist = LONG_MAX;
379 0 : const SmNode *pResult = 0;
380 :
381 0 : if (IsVisible())
382 0 : pResult = this;
383 : else
384 : {
385 0 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
386 0 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
387 0 : { const SmNode *pNode = GetSubNode(i);
388 :
389 0 : if (!pNode)
390 0 : continue;
391 :
392 : long nTmp;
393 0 : const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
394 0 : if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist)
395 0 : { nDist = nTmp;
396 0 : pResult = pFound;
397 :
398 : // quit immediately if 'rPoint' is inside the *should not
399 : // overlap with other rectangles* part.
400 : // This (partly) serves for getting the attributes in eg
401 : // "bar overstrike a".
402 : // ('nDist < 0' is used as *quick shot* to avoid evaluation of
403 : // the following expression, where the result is already determined)
404 0 : if (nDist < 0 && pFound->IsInsideRect(rPoint))
405 0 : break;
406 : }
407 : }
408 : }
409 :
410 0 : return pResult;
411 : }
412 :
413 0 : void SmNode::GetAccessibleText( OUStringBuffer &/*rText*/ ) const
414 : {
415 : SAL_WARN("starmath", "SmNode: GetAccessibleText not overridden");
416 0 : }
417 :
418 0 : const SmNode * SmNode::FindNodeWithAccessibleIndex(sal_Int32 nAccIdx) const
419 : {
420 0 : const SmNode *pResult = 0;
421 :
422 0 : sal_Int32 nIdx = GetAccessibleIndex();
423 0 : OUStringBuffer aTxt;
424 0 : if (nIdx >= 0)
425 0 : GetAccessibleText( aTxt ); // get text if used in following 'if' statement
426 :
427 0 : if (nIdx >= 0
428 0 : && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.getLength())
429 0 : pResult = this;
430 : else
431 : {
432 0 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
433 0 : for (sal_uInt16 i = 0; i < nNumSubNodes; i++)
434 : {
435 0 : const SmNode *pNode = GetSubNode(i);
436 0 : if (!pNode)
437 0 : continue;
438 :
439 0 : pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
440 0 : if (pResult)
441 0 : return pResult;
442 : }
443 : }
444 :
445 0 : return pResult;
446 : }
447 :
448 : #ifdef DEBUG_ENABLE_DUMPASDOT
449 : void SmNode::DumpAsDot(std::ostream &out, OUString* label, int number, int& id, int parent) const
450 : {
451 : //If this is the root start the file
452 : if(number == -1){
453 : out<<"digraph {"<<std::endl;
454 : if(label){
455 : out<<"labelloc = \"t\";"<<std::endl;
456 : OUString eq(*label);
457 : //CreateTextFromNode(eq);
458 : eq = eq.replaceAll("\n", " ");
459 : eq = eq.replaceAll("\\", "\\\\");
460 : eq = eq.replaceAll("\"", "\\\"");
461 : out<<"label= \"Equation: \\\"";
462 : out<< OUStringToOString(eq, RTL_TEXTENCODING_UTF8).getStr();
463 : out<<"\\\"\";"<<std::endl;
464 : }
465 : }
466 :
467 : //Some how out<<(int)this; doesn't work... So we do this nasty workaround...
468 : char strid[100];
469 : sprintf(strid, "%i", id);
470 :
471 : char strnr[100];
472 : sprintf(strnr, "%i", number);
473 :
474 : //Dump connection to this node
475 : if( parent != -1 ){
476 : char pid[100];
477 : sprintf(pid, "%i", parent);
478 : out<<"n"<<pid<<" -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
479 : //If doesn't have parent and isn't a rootnode:
480 : } else if(number != -1) {
481 : out<<"orphaned -> n"<<strid<<" [label=\""<<strnr<<"\"];"<<std::endl;
482 : }
483 :
484 : //Dump this node
485 : out<<"n"<< strid<<" [label=\"";
486 : switch( GetType() ) {
487 : case NTABLE: out<<"SmTableNode"; break;
488 : case NBRACE: out<<"SmBraceNode"; break;
489 : case NBRACEBODY: out<<"SmBracebodyNode"; break;
490 : case NOPER: out<<"SmOperNode"; break;
491 : case NALIGN: out<<"SmAlignNode"; break;
492 : case NATTRIBUT: out<<"SmAttributNode"; break;
493 : case NFONT: out<<"SmFontNode"; break;
494 : case NUNHOR: out<<"SmUnHorNode"; break;
495 : case NBINHOR: out<<"SmBinHorNode"; break;
496 : case NBINVER: out<<"SmBinVerNode"; break;
497 : case NBINDIAGONAL: out<<"SmBinDiagonalNode"; break;
498 : case NSUBSUP: out<<"SmSubSupNode"; break;
499 : case NMATRIX: out<<"SmMatrixNode"; break;
500 : case NPLACE: out<<"SmPlaceNode"; break;
501 : case NTEXT:
502 : out<<"SmTextNode: ";
503 : out<< OUStringToOString(((SmTextNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
504 : break;
505 : case NSPECIAL: out<<"SmSpecialNode"; break;
506 : case NGLYPH_SPECIAL: out<<"SmGlyphSpecialNode"; break;
507 : case NMATH:
508 : out<<"SmMathSymbolNode: ";
509 : out<< OUStringToOString(((SmMathSymbolNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).getStr();
510 : break;
511 : case NBLANK: out<<"SmBlankNode"; break;
512 : case NERROR: out<<"SmErrorNode"; break;
513 : case NLINE: out<<"SmLineNode"; break;
514 : case NEXPRESSION: out<<"SmExpressionNode"; break;
515 : case NPOLYLINE: out<<"SmPolyLineNode"; break;
516 : case NROOT: out<<"SmRootNode"; break;
517 : case NROOTSYMBOL: out<<"SmRootSymbolNode"; break;
518 : case NRECTANGLE: out<<"SmRectangleNode"; break;
519 : case NVERTICAL_BRACE: out<<"SmVerticalBraceNode"; break;
520 : case NMATHIDENT: out<<"SmMathIdentifierNode"; break;
521 : case NINTDYNSYMBOL: out<<"SmDynIntegralSymbolNode"; break;
522 : case NINTDYN: out<<"SmDynIntegralNode"; break;
523 : default:
524 : out<<"Unknown Node";
525 : }
526 : out<<"\"";
527 : if(IsSelected())
528 : out<<", style=dashed";
529 : out<<"];"<<std::endl;
530 :
531 : //Dump subnodes
532 : int myid = id;
533 : const SmNode *pNode;
534 : sal_uInt16 nSize = GetNumSubNodes();
535 : for (sal_uInt16 i = 0; i < nSize; i++)
536 : if (NULL != (pNode = GetSubNode(i)))
537 : pNode->DumpAsDot(out, NULL, i, ++id, myid);
538 :
539 : //If this is the root end the file
540 : if( number == -1 )
541 : out<<"}"<<std::endl;
542 : }
543 : #endif /* DEBUG_ENABLE_DUMPASDOT */
544 :
545 0 : long SmNode::GetFormulaBaseline() const
546 : {
547 : SAL_WARN("starmath", "This dummy implementation should not have been called.");
548 0 : return 0;
549 : }
550 :
551 :
552 :
553 0 : SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
554 0 : SmNode( rNode.GetType(), rNode.GetToken() )
555 : {
556 : size_t i;
557 0 : for (i = 0; i < aSubNodes.size(); i++)
558 0 : delete aSubNodes[i];
559 0 : aSubNodes.resize(0);
560 :
561 0 : auto nSize = rNode.aSubNodes.size();
562 0 : aSubNodes.resize( nSize );
563 0 : for (i = 0; i < nSize; ++i)
564 : {
565 0 : SmNode *pNode = rNode.aSubNodes[i];
566 0 : aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
567 : }
568 0 : ClaimPaternity();
569 0 : }
570 :
571 :
572 13532 : SmStructureNode::~SmStructureNode()
573 : {
574 : SmNode *pNode;
575 :
576 24582 : for (sal_uInt16 i = 0; i < GetNumSubNodes(); i++)
577 17816 : if (NULL != (pNode = GetSubNode(i)))
578 13925 : delete pNode;
579 6766 : }
580 :
581 :
582 0 : SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
583 : {
584 0 : SmNode::operator = ( rNode );
585 :
586 : size_t i;
587 0 : for (i = 0; i < aSubNodes.size(); i++)
588 0 : delete aSubNodes[i];
589 0 : aSubNodes.resize(0);
590 :
591 0 : auto nSize = rNode.aSubNodes.size();
592 0 : aSubNodes.resize( nSize );
593 0 : for (i = 0; i < nSize; ++i)
594 : {
595 0 : SmNode *pNode = rNode.aSubNodes[i];
596 0 : aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0;
597 : }
598 :
599 0 : ClaimPaternity();
600 :
601 0 : return *this;
602 : }
603 :
604 :
605 3021 : void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThird)
606 : {
607 3021 : size_t nSize = pThird ? 3 : (pSecond ? 2 : (pFirst ? 1 : 0));
608 3021 : aSubNodes.resize( nSize );
609 3021 : if (pFirst)
610 2509 : aSubNodes[0] = pFirst;
611 3021 : if (pSecond)
612 2654 : aSubNodes[1] = pSecond;
613 3021 : if (pThird)
614 1880 : aSubNodes[2] = pThird;
615 :
616 3021 : ClaimPaternity();
617 3021 : }
618 :
619 :
620 4044 : void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
621 : {
622 4044 : aSubNodes = rNodeArray;
623 4044 : ClaimPaternity();
624 4044 : }
625 :
626 :
627 73 : bool SmStructureNode::IsVisible() const
628 : {
629 73 : return false;
630 : }
631 :
632 :
633 92507 : sal_uInt16 SmStructureNode::GetNumSubNodes() const
634 : {
635 92507 : return (sal_uInt16) aSubNodes.size();
636 : }
637 :
638 :
639 216828 : SmNode * SmStructureNode::GetSubNode(sal_uInt16 nIndex)
640 : {
641 216828 : return aSubNodes[nIndex];
642 : }
643 :
644 :
645 0 : void SmStructureNode::GetAccessibleText( OUStringBuffer &rText ) const
646 : {
647 0 : sal_uInt16 nNodes = GetNumSubNodes();
648 0 : for (sal_uInt16 i = 0; i < nNodes; ++i)
649 : {
650 0 : SmNode *pNode = const_cast<SmStructureNode *>(this)->GetSubNode(i);
651 0 : if (pNode)
652 : {
653 0 : if (pNode->IsVisible())
654 0 : static_cast<SmStructureNode *>(pNode)->nAccIndex = rText.getLength();
655 0 : pNode->GetAccessibleText( rText );
656 : }
657 : }
658 0 : }
659 :
660 :
661 :
662 :
663 8 : bool SmVisibleNode::IsVisible() const
664 : {
665 8 : return true;
666 : }
667 :
668 :
669 36402 : sal_uInt16 SmVisibleNode::GetNumSubNodes() const
670 : {
671 36402 : return 0;
672 : }
673 :
674 :
675 0 : SmNode * SmVisibleNode::GetSubNode(sal_uInt16 /*nIndex*/)
676 : {
677 0 : return NULL;
678 : }
679 :
680 :
681 :
682 :
683 0 : void SmGraphicNode::GetAccessibleText( OUStringBuffer &rText ) const
684 : {
685 0 : rText.append(GetToken().aText);
686 0 : }
687 :
688 :
689 :
690 :
691 5 : void SmExpressionNode::CreateTextFromNode(OUString &rText)
692 : {
693 : SmNode *pNode;
694 5 : sal_uInt16 nSize = GetNumSubNodes();
695 5 : if (nSize > 1)
696 2 : rText += "{";
697 14 : for (sal_uInt16 i = 0; i < nSize; i++)
698 9 : if (NULL != (pNode = GetSubNode(i)))
699 : {
700 9 : pNode->CreateTextFromNode(rText);
701 : //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
702 9 : if (pNode->GetType() == NMATH)
703 4 : if ((nSize != 2) ||
704 0 : ( !rText.endsWith("+") && !rText.endsWith("-") ))
705 2 : rText += " ";
706 : }
707 :
708 5 : if (nSize > 1)
709 : {
710 2 : rText = comphelper::string::stripEnd(rText, ' ');
711 2 : rText += "} ";
712 : }
713 5 : }
714 :
715 :
716 :
717 :
718 1173 : void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
719 : // arranges all subnodes in one column
720 : {
721 : SmNode *pNode;
722 1173 : sal_uInt16 nSize = GetNumSubNodes();
723 :
724 : // make distance depend on font size
725 1173 : long nDist = +(rFormat.GetDistance(DIS_VERTICAL)
726 1173 : * GetFont().GetSize().Height()) / 100L;
727 :
728 1173 : if (nSize < 1)
729 1173 : return;
730 :
731 : // arrange subnodes and get maximum width of them
732 1173 : long nMaxWidth = 0,
733 : nTmp;
734 : sal_uInt16 i;
735 2444 : for (i = 0; i < nSize; i++)
736 1271 : if (NULL != (pNode = GetSubNode(i)))
737 1271 : { pNode->Arrange(rDev, rFormat);
738 1271 : if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
739 1216 : nMaxWidth = nTmp;
740 : }
741 :
742 1173 : Point aPos;
743 1173 : SmRect::operator = (SmRect(nMaxWidth, 1));
744 2444 : for (i = 0; i < nSize; i++)
745 1271 : { if (NULL != (pNode = GetSubNode(i)))
746 1271 : { const SmRect &rNodeRect = pNode->GetRect();
747 1271 : const SmNode *pCoNode = pNode->GetLeftMost();
748 1271 : RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
749 :
750 : aPos = rNodeRect.AlignTo(*this, RP_BOTTOM,
751 1271 : eHorAlign, RVA_BASELINE);
752 1271 : if (i)
753 98 : aPos.Y() += nDist;
754 1271 : pNode->MoveTo(aPos);
755 1271 : ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
756 : }
757 : }
758 : // #i972#
759 1173 : if (HasBaseline())
760 1006 : nFormulaBaseline = GetBaseline();
761 : else
762 : {
763 167 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
764 167 : aTmpDev.SetFont(GetFont());
765 :
766 : SmRect aRect = (SmRect(aTmpDev, &rFormat, OUString("a"),
767 167 : GetFont().GetBorderWidth()));
768 167 : nFormulaBaseline = GetAlignM();
769 : // move from middle position by constant - distance
770 : // between middle and baseline for single letter
771 167 : nFormulaBaseline += aRect.GetBaseline() - aRect.GetAlignM();
772 : }
773 : }
774 :
775 :
776 45 : SmNode * SmTableNode::GetLeftMost()
777 : {
778 45 : return this;
779 : }
780 :
781 :
782 561 : long SmTableNode::GetFormulaBaseline() const
783 : {
784 561 : return nFormulaBaseline;
785 : }
786 :
787 :
788 : /**************************************************************************/
789 :
790 :
791 2060 : void SmLineNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
792 : {
793 2060 : SmNode::Prepare(rFormat, rDocShell);
794 :
795 : // Here we use the 'FNT_VARIABLE' font since it's ascent and descent in general fit better
796 : // to the rest of the formula compared to the 'FNT_MATH' font.
797 2060 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
798 2060 : Flags() |= FLG_FONT;
799 2060 : }
800 :
801 :
802 : /**************************************************************************/
803 :
804 :
805 1977 : void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
806 : // arranges all subnodes in one row with some extra space between
807 : {
808 : SmNode *pNode;
809 1977 : sal_uInt16 nSize = GetNumSubNodes();
810 : sal_uInt16 i;
811 5210 : for (i = 0; i < nSize; i++)
812 3233 : if (NULL != (pNode = GetSubNode(i)))
813 3233 : pNode->Arrange(rDev, rFormat);
814 :
815 1977 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
816 1977 : aTmpDev.SetFont(GetFont());
817 :
818 1977 : if (nSize < 1)
819 : {
820 : // provide an empty rectangle with alignment parameters for the "current"
821 : // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
822 : // same sub-/supscript positions.)
823 : //! be sure to use a character that has explicitly defined HiAttribut
824 : //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
825 : //! 'vec {a}'.
826 : SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString("a"),
827 223 : GetFont().GetBorderWidth()));
828 : // make sure that the rectangle occupies (almost) no space
829 223 : SetWidth(1);
830 223 : SetItalicSpaces(0, 0);
831 2200 : return;
832 : }
833 :
834 : // make distance depend on font size
835 1754 : long nDist = (rFormat.GetDistance(DIS_HORIZONTAL) * GetFont().GetSize().Height()) / 100L;
836 1754 : if (!IsUseExtraSpaces())
837 0 : nDist = 0;
838 :
839 1754 : Point aPos;
840 : // copy the first node into LineNode and extend by the others
841 1754 : if (NULL != (pNode = GetSubNode(0)))
842 1754 : SmRect::operator = (pNode->GetRect());
843 :
844 3233 : for (i = 1; i < nSize; i++)
845 1479 : if (NULL != (pNode = GetSubNode(i)))
846 : {
847 1479 : aPos = pNode->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
848 :
849 : // add horizontal space to the left for each but the first sub node
850 1479 : aPos.X() += nDist;
851 :
852 1479 : pNode->MoveTo(aPos);
853 1479 : ExtendBy( *pNode, RCP_XOR );
854 1754 : }
855 : }
856 :
857 :
858 : /**************************************************************************/
859 :
860 :
861 894 : void SmExpressionNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
862 : // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
863 : {
864 894 : SmLineNode::Arrange(rDev, rFormat);
865 :
866 : // copy alignment of leftmost subnode if any
867 894 : SmNode *pNode = GetLeftMost();
868 894 : if (pNode)
869 894 : SetRectHorAlign(pNode->GetRectHorAlign(), false);
870 894 : }
871 :
872 :
873 : /**************************************************************************/
874 :
875 :
876 139 : void SmUnHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
877 : {
878 139 : bool bIsPostfix = GetToken().eType == TFACT;
879 :
880 139 : SmNode *pOper = GetSubNode(bIsPostfix ? 1 : 0),
881 139 : *pBody = GetSubNode(bIsPostfix ? 0 : 1);
882 : OSL_ENSURE(pOper, "Sm: NULL pointer");
883 : OSL_ENSURE(pBody, "Sm: NULL pointer");
884 :
885 139 : pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
886 139 : pOper->Arrange(rDev, rFormat);
887 139 : pBody->Arrange(rDev, rFormat);
888 :
889 : Point aPos = pOper->AlignTo(*pBody, bIsPostfix ? RP_RIGHT : RP_LEFT,
890 139 : RHA_CENTER, RVA_BASELINE);
891 : // add a bit space between operator and argument
892 : // (worst case -{1 over 2} where - and over have almost no space inbetween)
893 139 : long nDelta = pOper->GetFont().GetSize().Height() / 20;
894 139 : if (bIsPostfix)
895 0 : aPos.X() += nDelta;
896 : else
897 139 : aPos.X() -= nDelta;
898 139 : pOper->MoveTo(aPos);
899 :
900 139 : SmRect::operator = (*pBody);
901 139 : long nOldBot = GetBottom();
902 :
903 139 : ExtendBy(*pOper, RCP_XOR);
904 :
905 : // workaround for Bug 50865: "a^2 a^+2" have different baselines
906 : // for exponents (if size of exponent is large enough)
907 139 : SetBottom(nOldBot);
908 139 : }
909 :
910 :
911 : /**************************************************************************/
912 :
913 :
914 78 : void SmRootNode::GetHeightVerOffset(const SmRect &rRect,
915 : long &rHeight, long &rVerOffset)
916 : // calculate height and vertical offset of root sign suitable for 'rRect'
917 : {
918 78 : rVerOffset = (rRect.GetBottom() - rRect.GetAlignB()) / 2;
919 78 : rHeight = rRect.GetHeight() - rVerOffset;
920 :
921 : OSL_ENSURE(rHeight >= 0, "Sm : Ooops...");
922 : OSL_ENSURE(rVerOffset >= 0, "Sm : Ooops...");
923 78 : }
924 :
925 :
926 15 : Point SmRootNode::GetExtraPos(const SmRect &rRootSymbol,
927 : const SmRect &rExtra)
928 : {
929 15 : const Size &rSymSize = rRootSymbol.GetSize();
930 :
931 15 : Point aPos = rRootSymbol.GetTopLeft()
932 15 : + Point((rSymSize.Width() * 70) / 100,
933 45 : (rSymSize.Height() * 52) / 100);
934 :
935 : // from this calculate topleft edge of 'rExtra'
936 15 : aPos.X() -= rExtra.GetWidth() + rExtra.GetItalicRightSpace();
937 15 : aPos.Y() -= rExtra.GetHeight();
938 : // if there's enough space move a bit less to the right
939 : // examples: "nroot i a", "nroot j a"
940 : // (it looks better if we don't use italic-spaces here)
941 15 : long nX = rRootSymbol.GetLeft() + (rSymSize.Width() * 30) / 100;
942 15 : if (aPos.X() > nX)
943 0 : aPos.X() = nX;
944 :
945 15 : return aPos;
946 : }
947 :
948 :
949 78 : void SmRootNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
950 : {
951 : //! pExtra needs to have the smaller index than pRootSym in order to
952 : //! not to get the root symbol but the pExtra when clicking on it in the
953 : //! GraphicWindow. (That is because of the simplicity of the algorithm
954 : //! that finds the node corresponding to a mouseclick in the window.)
955 78 : SmNode *pExtra = GetSubNode(0),
956 78 : *pRootSym = GetSubNode(1),
957 78 : *pBody = GetSubNode(2);
958 : OSL_ENSURE(pRootSym, "Sm: NULL pointer");
959 : OSL_ENSURE(pBody, "Sm: NULL pointer");
960 :
961 78 : pBody->Arrange(rDev, rFormat);
962 :
963 : long nHeight,
964 : nVerOffset;
965 78 : GetHeightVerOffset(*pBody, nHeight, nVerOffset);
966 78 : nHeight += rFormat.GetDistance(DIS_ROOT)
967 78 : * GetFont().GetSize().Height() / 100L;
968 :
969 : // font specialist advised to change the width first
970 78 : pRootSym->AdaptToY(rDev, nHeight);
971 78 : pRootSym->AdaptToX(rDev, pBody->GetItalicWidth());
972 :
973 78 : pRootSym->Arrange(rDev, rFormat);
974 :
975 78 : Point aPos = pRootSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
976 : //! override calculated vertical position
977 78 : aPos.Y() = pRootSym->GetTop() + pBody->GetBottom() - pRootSym->GetBottom();
978 78 : aPos.Y() -= nVerOffset;
979 78 : pRootSym->MoveTo(aPos);
980 :
981 78 : if (pExtra)
982 15 : { pExtra->SetSize(Fraction(rFormat.GetRelSize(SIZ_INDEX), 100));
983 15 : pExtra->Arrange(rDev, rFormat);
984 :
985 15 : aPos = GetExtraPos(*pRootSym, *pExtra);
986 15 : pExtra->MoveTo(aPos);
987 : }
988 :
989 78 : SmRect::operator = (*pBody);
990 78 : ExtendBy(*pRootSym, RCP_THIS);
991 78 : if (pExtra)
992 15 : ExtendBy(*pExtra, RCP_THIS, true);
993 78 : }
994 :
995 :
996 0 : void SmRootNode::CreateTextFromNode(OUString &rText)
997 : {
998 0 : SmNode *pExtra = GetSubNode(0);
999 0 : if (pExtra)
1000 : {
1001 0 : rText += "nroot ";
1002 0 : pExtra->CreateTextFromNode(rText);
1003 : }
1004 : else
1005 0 : rText += "sqrt ";
1006 :
1007 0 : if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
1008 0 : rText += "{ ";
1009 :
1010 0 : GetSubNode(2)->CreateTextFromNode(rText);
1011 :
1012 0 : if (!pExtra && GetSubNode(2)->GetNumSubNodes() > 1)
1013 0 : rText += "} ";
1014 0 : }
1015 :
1016 : /**************************************************************************/
1017 :
1018 :
1019 0 : void SmDynIntegralNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1020 : {
1021 0 : SmNode *pDynIntegralSym = Symbol(),
1022 0 : *pBody = Body();
1023 : OSL_ENSURE(pDynIntegralSym, "Sm: NULL pointer");
1024 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1025 :
1026 0 : pBody->Arrange(rDev, rFormat);
1027 :
1028 0 : long nHeight = pBody->GetHeight();
1029 0 : pDynIntegralSym->AdaptToY(rDev, nHeight);
1030 :
1031 0 : pDynIntegralSym->Arrange(rDev, rFormat);
1032 :
1033 0 : Point aPos = pDynIntegralSym->AlignTo(*pBody, RP_LEFT, RHA_CENTER, RVA_BASELINE);
1034 : //! override calculated vertical position
1035 0 : aPos.Y() = pDynIntegralSym->GetTop() + pBody->GetBottom() - pDynIntegralSym->GetBottom();
1036 0 : pDynIntegralSym->MoveTo(aPos);
1037 :
1038 :
1039 : // override its own rectangle with pBody's
1040 0 : SmRect::operator = (*pBody);
1041 : // extends this rectangle with the symbol's one
1042 0 : ExtendBy(*pDynIntegralSym, RCP_THIS);
1043 :
1044 0 : }
1045 :
1046 :
1047 0 : void SmDynIntegralNode::CreateTextFromNode(OUString &rText)
1048 : {
1049 :
1050 0 : rText += "intd ";
1051 0 : SmNode *pBody = GetSubNode(1);
1052 :
1053 0 : if (pBody->GetNumSubNodes() > 1)
1054 0 : rText += "{ ";
1055 :
1056 0 : pBody->CreateTextFromNode(rText);
1057 :
1058 0 : if (pBody->GetNumSubNodes() > 1)
1059 0 : rText += "} ";
1060 0 : }
1061 :
1062 :
1063 :
1064 : /**************************************************************************/
1065 :
1066 :
1067 826 : void SmBinHorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1068 : {
1069 826 : SmNode *pLeft = GetSubNode(0),
1070 826 : *pOper = GetSubNode(1),
1071 826 : *pRight = GetSubNode(2);
1072 : OSL_ENSURE(pLeft != NULL, "Sm: NULL pointer");
1073 : OSL_ENSURE(pOper != NULL, "Sm: NULL pointer");
1074 : OSL_ENSURE(pRight != NULL, "Sm: NULL pointer");
1075 :
1076 826 : pOper->SetSize(Fraction (rFormat.GetRelSize(SIZ_OPERATOR), 100));
1077 :
1078 826 : pLeft ->Arrange(rDev, rFormat);
1079 826 : pOper ->Arrange(rDev, rFormat);
1080 826 : pRight->Arrange(rDev, rFormat);
1081 :
1082 826 : const SmRect &rOpRect = pOper->GetRect();
1083 :
1084 1652 : long nDist = (rOpRect.GetWidth() *
1085 1652 : rFormat.GetDistance(DIS_HORIZONTAL)) / 100L;
1086 :
1087 826 : SmRect::operator = (*pLeft);
1088 :
1089 826 : Point aPos;
1090 826 : aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1091 826 : aPos.X() += nDist;
1092 826 : pOper->MoveTo(aPos);
1093 826 : ExtendBy(*pOper, RCP_XOR);
1094 :
1095 826 : aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1096 826 : aPos.X() += nDist;
1097 :
1098 826 : pRight->MoveTo(aPos);
1099 826 : ExtendBy(*pRight, RCP_XOR);
1100 826 : }
1101 :
1102 :
1103 : /**************************************************************************/
1104 :
1105 :
1106 239 : void SmBinVerNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1107 : {
1108 239 : SmNode *pNum = GetSubNode(0),
1109 239 : *pLine = GetSubNode(1),
1110 239 : *pDenom = GetSubNode(2);
1111 : OSL_ENSURE(pNum, "Sm : NULL pointer");
1112 : OSL_ENSURE(pLine, "Sm : NULL pointer");
1113 : OSL_ENSURE(pDenom, "Sm : NULL pointer");
1114 :
1115 239 : bool bIsTextmode = rFormat.IsTextmode();
1116 239 : if (bIsTextmode)
1117 : {
1118 0 : Fraction aFraction(rFormat.GetRelSize(SIZ_INDEX), 100);
1119 0 : pNum ->SetSize(aFraction);
1120 0 : pLine ->SetSize(aFraction);
1121 0 : pDenom->SetSize(aFraction);
1122 : }
1123 :
1124 239 : pNum ->Arrange(rDev, rFormat);
1125 239 : pDenom->Arrange(rDev, rFormat);
1126 :
1127 239 : long nFontHeight = GetFont().GetSize().Height(),
1128 239 : nExtLen = nFontHeight * rFormat.GetDistance(DIS_FRACTION) / 100L,
1129 239 : nThick = nFontHeight * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L,
1130 239 : nWidth = std::max(pNum->GetItalicWidth(), pDenom->GetItalicWidth()),
1131 : nNumDist = bIsTextmode ? 0 :
1132 239 : nFontHeight * rFormat.GetDistance(DIS_NUMERATOR) / 100L,
1133 : nDenomDist = bIsTextmode ? 0 :
1134 239 : nFontHeight * rFormat.GetDistance(DIS_DENOMINATOR) / 100L;
1135 :
1136 : // font specialist advised to change the width first
1137 239 : pLine->AdaptToY(rDev, nThick);
1138 239 : pLine->AdaptToX(rDev, nWidth + 2 * nExtLen);
1139 239 : pLine->Arrange(rDev, rFormat);
1140 :
1141 : // get horizontal alignment for numerator
1142 239 : const SmNode *pLM = pNum->GetLeftMost();
1143 239 : RectHorAlign eHorAlign = pLM->GetRectHorAlign();
1144 :
1145 : // move numerator to its position
1146 239 : Point aPos = pNum->AlignTo(*pLine, RP_TOP, eHorAlign, RVA_BASELINE);
1147 239 : aPos.Y() -= nNumDist;
1148 239 : pNum->MoveTo(aPos);
1149 :
1150 : // get horizontal alignment for denominator
1151 239 : pLM = pDenom->GetLeftMost();
1152 239 : eHorAlign = pLM->GetRectHorAlign();
1153 :
1154 : // move denominator to its position
1155 239 : aPos = pDenom->AlignTo(*pLine, RP_BOTTOM, eHorAlign, RVA_BASELINE);
1156 239 : aPos.Y() += nDenomDist;
1157 239 : pDenom->MoveTo(aPos);
1158 :
1159 239 : SmRect::operator = (*pNum);
1160 239 : ExtendBy(*pDenom, RCP_NONE).ExtendBy(*pLine, RCP_NONE, pLine->GetCenterY());
1161 239 : }
1162 :
1163 0 : void SmBinVerNode::CreateTextFromNode(OUString &rText)
1164 : {
1165 0 : SmNode *pNum = GetSubNode(0),
1166 0 : *pDenom = GetSubNode(2);
1167 0 : pNum->CreateTextFromNode(rText);
1168 0 : rText += "over ";
1169 0 : pDenom->CreateTextFromNode(rText);
1170 0 : }
1171 :
1172 :
1173 42 : SmNode * SmBinVerNode::GetLeftMost()
1174 : {
1175 42 : return this;
1176 : }
1177 :
1178 :
1179 : namespace {
1180 :
1181 : /// @return value of the determinant formed by the two points
1182 68 : double Det(const Point &rHeading1, const Point &rHeading2)
1183 : {
1184 68 : return rHeading1.X() * rHeading2.Y() - rHeading1.Y() * rHeading2.X();
1185 : }
1186 :
1187 :
1188 : /// Is true iff the point 'rPoint1' belongs to the straight line through 'rPoint2'
1189 : /// and has the direction vector 'rHeading2'
1190 0 : bool IsPointInLine(const Point &rPoint1,
1191 : const Point &rPoint2, const Point &rHeading2)
1192 : {
1193 : OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1194 :
1195 0 : bool bRes = false;
1196 : static const double eps = 5.0 * DBL_EPSILON;
1197 :
1198 : double fLambda;
1199 0 : if (labs(rHeading2.X()) > labs(rHeading2.Y()))
1200 : {
1201 0 : fLambda = (rPoint1.X() - rPoint2.X()) / (double) rHeading2.X();
1202 0 : bRes = fabs(rPoint1.Y() - (rPoint2.Y() + fLambda * rHeading2.Y())) < eps;
1203 : }
1204 : else
1205 : {
1206 0 : fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
1207 0 : bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
1208 : }
1209 :
1210 0 : return bRes;
1211 : }
1212 :
1213 :
1214 68 : sal_uInt16 GetLineIntersectionPoint(Point &rResult,
1215 : const Point& rPoint1, const Point &rHeading1,
1216 : const Point& rPoint2, const Point &rHeading2)
1217 : {
1218 : OSL_ENSURE(rHeading1 != Point(), "Sm : 0 vector");
1219 : OSL_ENSURE(rHeading2 != Point(), "Sm : 0 vector");
1220 :
1221 68 : sal_uInt16 nRes = 1;
1222 : static const double eps = 5.0 * DBL_EPSILON;
1223 :
1224 : // are the direction vectors linearly dependent?
1225 68 : double fDet = Det(rHeading1, rHeading2);
1226 68 : if (fabs(fDet) < eps)
1227 : {
1228 0 : nRes = IsPointInLine(rPoint1, rPoint2, rHeading2) ? USHRT_MAX : 0;
1229 0 : rResult = nRes ? rPoint1 : Point();
1230 : }
1231 : else
1232 : {
1233 : // here we do not pay attention to the computational accurancy
1234 : // (that would be more complicated and is not really worth it in this case)
1235 68 : double fLambda = ( (rPoint1.Y() - rPoint2.Y()) * rHeading2.X()
1236 68 : - (rPoint1.X() - rPoint2.X()) * rHeading2.Y())
1237 68 : / fDet;
1238 68 : rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
1239 136 : rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
1240 : }
1241 :
1242 68 : return nRes;
1243 : }
1244 :
1245 : }
1246 :
1247 :
1248 34 : SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
1249 34 : : SmStructureNode(NBINDIAGONAL, rNodeToken)
1250 : {
1251 34 : bAscending = false;
1252 34 : SetNumSubNodes(3);
1253 34 : }
1254 :
1255 :
1256 : /// @return position and size of the diagonal line
1257 : /// premise: SmRect of the node defines the limitation(!) consequently it has to be known upfront
1258 34 : void SmBinDiagonalNode::GetOperPosSize(Point &rPos, Size &rSize,
1259 : const Point &rDiagPoint, double fAngleDeg) const
1260 :
1261 : {
1262 : static const double fPi = 3.1415926535897932384626433;
1263 34 : double fAngleRad = fAngleDeg / 180.0 * fPi;
1264 34 : long nRectLeft = GetItalicLeft(),
1265 34 : nRectRight = GetItalicRight(),
1266 34 : nRectTop = GetTop(),
1267 34 : nRectBottom = GetBottom();
1268 34 : Point aRightHdg (100, 0),
1269 34 : aDownHdg (0, 100),
1270 34 : aDiagHdg ( (long)(100.0 * cos(fAngleRad)),
1271 68 : (long)(-100.0 * sin(fAngleRad)) );
1272 :
1273 : long nLeft, nRight, nTop, nBottom; // margins of the rectangle for the diagonal
1274 34 : Point aPoint;
1275 34 : if (IsAscending())
1276 : {
1277 : // determine top right corner
1278 : GetLineIntersectionPoint(aPoint,
1279 : Point(nRectLeft, nRectTop), aRightHdg,
1280 17 : rDiagPoint, aDiagHdg);
1281 : // is there a point of intersection with the top border?
1282 17 : if (aPoint.X() <= nRectRight)
1283 : {
1284 17 : nRight = aPoint.X();
1285 17 : nTop = nRectTop;
1286 : }
1287 : else
1288 : {
1289 : // there has to be a point of intersection with the right border!
1290 : GetLineIntersectionPoint(aPoint,
1291 : Point(nRectRight, nRectTop), aDownHdg,
1292 0 : rDiagPoint, aDiagHdg);
1293 :
1294 0 : nRight = nRectRight;
1295 0 : nTop = aPoint.Y();
1296 : }
1297 :
1298 : // determine bottom left corner
1299 : GetLineIntersectionPoint(aPoint,
1300 : Point(nRectLeft, nRectBottom), aRightHdg,
1301 17 : rDiagPoint, aDiagHdg);
1302 : // is there a point of intersection with the bottom border?
1303 17 : if (aPoint.X() >= nRectLeft)
1304 : {
1305 17 : nLeft = aPoint.X();
1306 17 : nBottom = nRectBottom;
1307 : }
1308 : else
1309 : {
1310 : // there has to be a point of intersection with the left border!
1311 : GetLineIntersectionPoint(aPoint,
1312 : Point(nRectLeft, nRectTop), aDownHdg,
1313 0 : rDiagPoint, aDiagHdg);
1314 :
1315 0 : nLeft = nRectLeft;
1316 0 : nBottom = aPoint.Y();
1317 : }
1318 : }
1319 : else
1320 : {
1321 : // determine top left corner
1322 : GetLineIntersectionPoint(aPoint,
1323 : Point(nRectLeft, nRectTop), aRightHdg,
1324 17 : rDiagPoint, aDiagHdg);
1325 : // is there a point of intersection with the top border?
1326 17 : if (aPoint.X() >= nRectLeft)
1327 : {
1328 17 : nLeft = aPoint.X();
1329 17 : nTop = nRectTop;
1330 : }
1331 : else
1332 : {
1333 : // there has to be a point of intersection with the left border!
1334 : GetLineIntersectionPoint(aPoint,
1335 : Point(nRectLeft, nRectTop), aDownHdg,
1336 0 : rDiagPoint, aDiagHdg);
1337 :
1338 0 : nLeft = nRectLeft;
1339 0 : nTop = aPoint.Y();
1340 : }
1341 :
1342 : // determine bottom right corner
1343 : GetLineIntersectionPoint(aPoint,
1344 : Point(nRectLeft, nRectBottom), aRightHdg,
1345 17 : rDiagPoint, aDiagHdg);
1346 : // is there a point of intersection with the bottom border?
1347 17 : if (aPoint.X() <= nRectRight)
1348 : {
1349 17 : nRight = aPoint.X();
1350 17 : nBottom = nRectBottom;
1351 : }
1352 : else
1353 : {
1354 : // there has to be a point of intersection with the right border!
1355 : GetLineIntersectionPoint(aPoint,
1356 : Point(nRectRight, nRectTop), aDownHdg,
1357 0 : rDiagPoint, aDiagHdg);
1358 :
1359 0 : nRight = nRectRight;
1360 0 : nBottom = aPoint.Y();
1361 : }
1362 : }
1363 :
1364 34 : rSize = Size(nRight - nLeft + 1, nBottom - nTop + 1);
1365 34 : rPos.X() = nLeft;
1366 34 : rPos.Y() = nTop;
1367 34 : }
1368 :
1369 :
1370 34 : void SmBinDiagonalNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1371 : {
1372 : // Both arguments have to get into the SubNodes before the Operator so that clicking
1373 : // within the GraphicWindow sets the FormulaCursor correctly (cf. SmRootNode)
1374 34 : SmNode *pLeft = GetSubNode(0),
1375 34 : *pRight = GetSubNode(1);
1376 : OSL_ENSURE(pLeft, "Sm : NULL pointer");
1377 : OSL_ENSURE(pRight, "Sm : NULL pointer");
1378 :
1379 : OSL_ENSURE(GetSubNode(2)->GetType() == NPOLYLINE, "Sm : wrong node type");
1380 34 : SmPolyLineNode *pOper = static_cast<SmPolyLineNode *>(GetSubNode(2));
1381 : OSL_ENSURE(pOper, "Sm : NULL pointer");
1382 :
1383 : //! some routines being called extract some info from the OutputDevice's
1384 : //! font (eg the space to be used for borders OR the font name(!!)).
1385 : //! Thus the font should reflect the needs and has to be set!
1386 34 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1387 34 : aTmpDev.SetFont(GetFont());
1388 :
1389 34 : pLeft->Arrange(aTmpDev, rFormat);
1390 34 : pRight->Arrange(aTmpDev, rFormat);
1391 :
1392 : // determine implicitly the values (incl. the margin) of the diagonal line
1393 34 : pOper->Arrange(aTmpDev, rFormat);
1394 :
1395 34 : long nDelta = pOper->GetWidth() * 8 / 10;
1396 :
1397 : // determine TopLeft position from the right argument
1398 34 : Point aPos;
1399 34 : aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
1400 34 : if (IsAscending())
1401 17 : aPos.Y() = pLeft->GetBottom() + nDelta;
1402 : else
1403 17 : aPos.Y() = pLeft->GetTop() - nDelta - pRight->GetHeight();
1404 :
1405 34 : pRight->MoveTo(aPos);
1406 :
1407 : // determine new baseline
1408 51 : long nTmpBaseline = IsAscending() ? (pLeft->GetBottom() + pRight->GetTop()) / 2
1409 51 : : (pLeft->GetTop() + pRight->GetBottom()) / 2;
1410 34 : Point aLogCenter ((pLeft->GetItalicRight() + pRight->GetItalicLeft()) / 2,
1411 34 : nTmpBaseline);
1412 :
1413 34 : SmRect::operator = (*pLeft);
1414 34 : ExtendBy(*pRight, RCP_NONE);
1415 :
1416 :
1417 : // determine position and size of diagonal line
1418 34 : Size aTmpSize;
1419 34 : GetOperPosSize(aPos, aTmpSize, aLogCenter, IsAscending() ? 60.0 : -60.0);
1420 :
1421 : // font specialist advised to change the width first
1422 34 : pOper->AdaptToY(aTmpDev, aTmpSize.Height());
1423 34 : pOper->AdaptToX(aTmpDev, aTmpSize.Width());
1424 : // and make it active
1425 34 : pOper->Arrange(aTmpDev, rFormat);
1426 :
1427 34 : pOper->MoveTo(aPos);
1428 :
1429 34 : ExtendBy(*pOper, RCP_NONE, nTmpBaseline);
1430 34 : }
1431 :
1432 :
1433 : /**************************************************************************/
1434 :
1435 :
1436 744 : void SmSubSupNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1437 : {
1438 : OSL_ENSURE(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES,
1439 : "Sm: wrong number of subnodes");
1440 :
1441 744 : SmNode *pBody = GetBody();
1442 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1443 :
1444 744 : long nOrigHeight = pBody->GetFont().GetSize().Height();
1445 :
1446 744 : pBody->Arrange(rDev, rFormat);
1447 :
1448 744 : const SmRect &rBodyRect = pBody->GetRect();
1449 744 : SmRect::operator = (rBodyRect);
1450 :
1451 : // line that separates sub- and supscript rectangles
1452 744 : long nDelimLine = SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1453 :
1454 744 : Point aPos;
1455 : long nDelta, nDist;
1456 :
1457 : // iterate over all possible sub-/supscripts
1458 744 : SmRect aTmpRect (rBodyRect);
1459 5208 : for (int i = 0; i < SUBSUP_NUM_ENTRIES; i++)
1460 4464 : { SmSubSup eSubSup = (SmSubSup) i; // cast
1461 4464 : SmNode *pSubSup = GetSubSup(eSubSup);
1462 :
1463 4464 : if (!pSubSup)
1464 3472 : continue;
1465 :
1466 : // switch position of limits if we are in textmode
1467 992 : if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT))
1468 0 : switch (eSubSup)
1469 0 : { case CSUB: eSubSup = RSUB; break;
1470 0 : case CSUP: eSubSup = RSUP; break;
1471 : default:
1472 0 : break;
1473 : }
1474 :
1475 : // prevent sub-/supscripts from diminishing in size
1476 : // (as would be in "a_{1_{2_{3_4}}}")
1477 992 : if (GetFont().GetSize().Height() > rFormat.GetBaseSize().Height() / 3)
1478 : {
1479 830 : sal_uInt16 nIndex = (eSubSup == CSUB || eSubSup == CSUP) ?
1480 1301 : SIZ_LIMITS : SIZ_INDEX;
1481 992 : Fraction aFraction ( rFormat.GetRelSize(nIndex), 100 );
1482 992 : pSubSup->SetSize(aFraction);
1483 : }
1484 :
1485 992 : pSubSup->Arrange(rDev, rFormat);
1486 :
1487 992 : bool bIsTextmode = rFormat.IsTextmode();
1488 992 : nDist = 0;
1489 :
1490 : //! be sure that CSUB, CSUP are handled before the other cases!
1491 992 : switch (eSubSup)
1492 : { case RSUB :
1493 : case LSUB :
1494 236 : if (!bIsTextmode)
1495 : nDist = nOrigHeight
1496 236 : * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
1497 236 : aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1498 : eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
1499 472 : RHA_CENTER, RVA_BOTTOM);
1500 236 : aPos.Y() += nDist;
1501 236 : nDelta = nDelimLine - aPos.Y();
1502 236 : if (nDelta > 0)
1503 236 : aPos.Y() += nDelta;
1504 236 : break;
1505 : case RSUP :
1506 : case LSUP :
1507 447 : if (!bIsTextmode)
1508 : nDist = nOrigHeight
1509 447 : * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
1510 447 : aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1511 : eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
1512 894 : RHA_CENTER, RVA_TOP);
1513 447 : aPos.Y() -= nDist;
1514 447 : nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1515 447 : if (nDelta > 0)
1516 9 : aPos.Y() -= nDelta;
1517 447 : break;
1518 : case CSUB :
1519 162 : if (!bIsTextmode)
1520 : nDist = nOrigHeight
1521 162 : * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
1522 162 : aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
1523 162 : RHA_CENTER, RVA_BASELINE);
1524 162 : aPos.Y() += nDist;
1525 162 : break;
1526 : case CSUP :
1527 147 : if (!bIsTextmode)
1528 : nDist = nOrigHeight
1529 147 : * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
1530 147 : aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
1531 147 : RHA_CENTER, RVA_BASELINE);
1532 147 : aPos.Y() -= nDist;
1533 147 : break;
1534 : }
1535 :
1536 992 : pSubSup->MoveTo(aPos);
1537 992 : ExtendBy(*pSubSup, RCP_THIS, true);
1538 :
1539 : // update rectangle to which RSUB, RSUP, LSUB, LSUP
1540 : // will be aligned to
1541 992 : if (eSubSup == CSUB || eSubSup == CSUP)
1542 309 : aTmpRect = *this;
1543 : }
1544 744 : }
1545 :
1546 2 : void SmSubSupNode::CreateTextFromNode(OUString &rText)
1547 : {
1548 : SmNode *pNode;
1549 2 : GetSubNode(0)->CreateTextFromNode(rText);
1550 :
1551 2 : if (NULL != (pNode = GetSubNode(LSUB+1)))
1552 : {
1553 0 : rText += "lsub ";
1554 0 : pNode->CreateTextFromNode(rText);
1555 : }
1556 2 : if (NULL != (pNode = GetSubNode(LSUP+1)))
1557 : {
1558 0 : rText += "lsup ";
1559 0 : pNode->CreateTextFromNode(rText);
1560 : }
1561 2 : if (NULL != (pNode = GetSubNode(CSUB+1)))
1562 : {
1563 0 : rText += "csub ";
1564 0 : pNode->CreateTextFromNode(rText);
1565 : }
1566 2 : if (NULL != (pNode = GetSubNode(CSUP+1)))
1567 : {
1568 0 : rText += "csup ";
1569 0 : pNode->CreateTextFromNode(rText);
1570 : }
1571 2 : if (NULL != (pNode = GetSubNode(RSUB+1)))
1572 : {
1573 0 : rText = comphelper::string::stripEnd(rText, ' ');
1574 0 : rText += "_";
1575 0 : pNode->CreateTextFromNode(rText);
1576 : }
1577 2 : if (NULL != (pNode = GetSubNode(RSUP+1)))
1578 : {
1579 2 : rText = comphelper::string::stripEnd(rText, ' ');
1580 2 : rText += "^";
1581 2 : pNode->CreateTextFromNode(rText);
1582 : }
1583 2 : }
1584 :
1585 :
1586 : /**************************************************************************/
1587 :
1588 2 : void SmBraceNode::CreateTextFromNode(OUString &rText)
1589 : {
1590 2 : if (GetScaleMode() == SCALE_HEIGHT)
1591 2 : rText += "left ";
1592 : {
1593 2 : OUString aStr;
1594 2 : GetSubNode(0)->CreateTextFromNode(aStr);
1595 2 : aStr = comphelper::string::strip(aStr, ' ');
1596 2 : aStr = comphelper::string::stripStart(aStr, '\\');
1597 2 : if (!aStr.isEmpty())
1598 : {
1599 2 : if (aStr == "divides")
1600 0 : rText += "lline";
1601 2 : else if (aStr == "parallel")
1602 0 : rText += "ldline";
1603 2 : else if (aStr == "<")
1604 0 : rText += "langle";
1605 : else
1606 2 : rText += aStr;
1607 2 : rText += " ";
1608 : }
1609 : else
1610 0 : rText += "none ";
1611 : }
1612 2 : GetSubNode(1)->CreateTextFromNode(rText);
1613 2 : if (GetScaleMode() == SCALE_HEIGHT)
1614 2 : rText += "right ";
1615 : {
1616 2 : OUString aStr;
1617 2 : GetSubNode(2)->CreateTextFromNode(aStr);
1618 2 : aStr = comphelper::string::strip(aStr, ' ');
1619 2 : aStr = comphelper::string::stripStart(aStr, '\\');
1620 2 : if (!aStr.isEmpty())
1621 : {
1622 2 : if (aStr == "divides")
1623 0 : rText += "rline";
1624 2 : else if (aStr == "parallel")
1625 0 : rText += "rdline";
1626 2 : else if (aStr == ">")
1627 0 : rText += "rangle";
1628 : else
1629 2 : rText += aStr;
1630 2 : rText += " ";
1631 : }
1632 : else
1633 0 : rText += "none ";
1634 : }
1635 2 : rText += " ";
1636 :
1637 2 : }
1638 :
1639 442 : void SmBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1640 : {
1641 442 : SmNode *pLeft = GetSubNode(0),
1642 442 : *pBody = GetSubNode(1),
1643 442 : *pRight = GetSubNode(2);
1644 : OSL_ENSURE(pLeft, "Sm: NULL pointer");
1645 : OSL_ENSURE(pBody, "Sm: NULL pointer");
1646 : OSL_ENSURE(pRight, "Sm: NULL pointer");
1647 :
1648 442 : pBody->Arrange(rDev, rFormat);
1649 :
1650 442 : bool bIsScaleNormal = rFormat.IsScaleNormalBrackets(),
1651 1260 : bScale = pBody->GetHeight() > 0 &&
1652 851 : (GetScaleMode() == SCALE_HEIGHT || bIsScaleNormal),
1653 442 : bIsABS = GetToken().eType == TABS;
1654 :
1655 442 : long nFaceHeight = GetFont().GetSize().Height();
1656 :
1657 : // determine oversize in %
1658 442 : sal_uInt16 nPerc = 0;
1659 442 : if (!bIsABS && bScale)
1660 : { // in case of oversize braces...
1661 409 : sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1662 409 : DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1663 409 : nPerc = rFormat.GetDistance(nIndex);
1664 : }
1665 :
1666 : // determine the height for the braces
1667 : long nBraceHeight;
1668 442 : if (bScale)
1669 : {
1670 409 : nBraceHeight = pBody->GetType() == NBRACEBODY ?
1671 : static_cast<SmBracebodyNode *>(pBody)->GetBodyHeight()
1672 409 : : pBody->GetHeight();
1673 409 : nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
1674 : }
1675 : else
1676 33 : nBraceHeight = nFaceHeight;
1677 :
1678 : // distance to the argument
1679 442 : nPerc = bIsABS ? 0 : rFormat.GetDistance(DIS_BRACKETSPACE);
1680 442 : long nDist = nFaceHeight * nPerc / 100L;
1681 :
1682 : // if wanted, scale the braces to the wanted size
1683 442 : if (bScale)
1684 : {
1685 409 : Size aTmpSize (pLeft->GetFont().GetSize());
1686 : OSL_ENSURE(pRight->GetFont().GetSize() == aTmpSize,
1687 : "Sm : different font sizes");
1688 818 : aTmpSize.Width() = std::min((long) nBraceHeight * 60L / 100L,
1689 818 : rFormat.GetBaseSize().Height() * 3L / 2L);
1690 : // correction factor since change from StarMath to OpenSymbol font
1691 : // because of the different font width in the FontMetric
1692 409 : aTmpSize.Width() *= 182;
1693 409 : aTmpSize.Width() /= 267;
1694 :
1695 409 : sal_Unicode cChar = pLeft->GetToken().cMathChar;
1696 409 : if (cChar != MS_LINE && cChar != MS_DLINE &&
1697 391 : cChar != MS_VERTLINE && cChar != MS_DVERTLINE)
1698 373 : pLeft ->GetFont().SetSize(aTmpSize);
1699 :
1700 409 : cChar = pRight->GetToken().cMathChar;
1701 409 : if (cChar != MS_LINE && cChar != MS_DLINE &&
1702 391 : cChar != MS_VERTLINE && cChar != MS_DVERTLINE)
1703 373 : pRight->GetFont().SetSize(aTmpSize);
1704 :
1705 409 : pLeft ->AdaptToY(rDev, nBraceHeight);
1706 409 : pRight->AdaptToY(rDev, nBraceHeight);
1707 : }
1708 :
1709 442 : pLeft ->Arrange(rDev, rFormat);
1710 442 : pRight->Arrange(rDev, rFormat);
1711 :
1712 : // required in order to make "\(a\) - (a) - left ( a right )" look alright
1713 442 : RectVerAlign eVerAlign = bScale ? RVA_CENTERY : RVA_BASELINE;
1714 :
1715 442 : Point aPos;
1716 442 : aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
1717 442 : aPos.X() -= nDist;
1718 442 : pLeft->MoveTo(aPos);
1719 :
1720 442 : aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
1721 442 : aPos.X() += nDist;
1722 442 : pRight->MoveTo(aPos);
1723 :
1724 442 : SmRect::operator = (*pBody);
1725 442 : ExtendBy(*pLeft, RCP_THIS).ExtendBy(*pRight, RCP_THIS);
1726 442 : }
1727 :
1728 :
1729 : /**************************************************************************/
1730 :
1731 :
1732 442 : void SmBracebodyNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1733 : {
1734 442 : sal_uInt16 nNumSubNodes = GetNumSubNodes();
1735 442 : if (nNumSubNodes == 0)
1736 475 : return;
1737 :
1738 : // arrange arguments
1739 : sal_uInt16 i;
1740 872 : for (i = 0; i < nNumSubNodes; i += 2)
1741 463 : GetSubNode(i)->Arrange(rDev, rFormat);
1742 :
1743 : // build reference rectangle with necessary info for vertical alignment
1744 409 : SmRect aRefRect (*GetSubNode(0));
1745 872 : for (i = 0; i < nNumSubNodes; i += 2)
1746 : {
1747 463 : SmRect aTmpRect (*GetSubNode(i));
1748 463 : Point aPos = aTmpRect.AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1749 463 : aTmpRect.MoveTo(aPos);
1750 463 : aRefRect.ExtendBy(aTmpRect, RCP_XOR);
1751 : }
1752 :
1753 409 : nBodyHeight = aRefRect.GetHeight();
1754 :
1755 : // scale separators to required height and arrange them
1756 409 : bool bScale = GetScaleMode() == SCALE_HEIGHT || rFormat.IsScaleNormalBrackets();
1757 409 : long nHeight = bScale ? aRefRect.GetHeight() : GetFont().GetSize().Height();
1758 409 : sal_uInt16 nIndex = GetScaleMode() == SCALE_HEIGHT ?
1759 409 : DIS_BRACKETSIZE : DIS_NORMALBRACKETSIZE;
1760 409 : sal_uInt16 nPerc = rFormat.GetDistance(nIndex);
1761 409 : if (bScale)
1762 409 : nHeight += 2 * (nHeight * nPerc / 100L);
1763 463 : for (i = 1; i < nNumSubNodes; i += 2)
1764 : {
1765 54 : SmNode *pNode = GetSubNode(i);
1766 54 : pNode->AdaptToY(rDev, nHeight);
1767 54 : pNode->Arrange(rDev, rFormat);
1768 : }
1769 :
1770 : // horizontal distance between argument and brackets or separators
1771 409 : long nDist = GetFont().GetSize().Height()
1772 409 : * rFormat.GetDistance(DIS_BRACKETSPACE) / 100L;
1773 :
1774 409 : SmNode *pLeft = GetSubNode(0);
1775 409 : SmRect::operator = (*pLeft);
1776 517 : for (i = 1; i < nNumSubNodes; i++)
1777 : {
1778 108 : bool bIsSeparator = i % 2 != 0;
1779 108 : RectVerAlign eVerAlign = bIsSeparator ? RVA_CENTERY : RVA_BASELINE;
1780 :
1781 108 : SmNode *pRight = GetSubNode(i);
1782 108 : Point aPosX = pRight->AlignTo(*pLeft, RP_RIGHT, RHA_CENTER, eVerAlign),
1783 108 : aPosY = pRight->AlignTo(aRefRect, RP_RIGHT, RHA_CENTER, eVerAlign);
1784 108 : aPosX.X() += nDist;
1785 :
1786 108 : pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1787 108 : ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
1788 :
1789 108 : pLeft = pRight;
1790 : }
1791 : }
1792 :
1793 :
1794 : /**************************************************************************/
1795 :
1796 :
1797 36 : void SmVerticalBraceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1798 : {
1799 36 : SmNode *pBody = GetSubNode(0),
1800 36 : *pBrace = GetSubNode(1),
1801 36 : *pScript = GetSubNode(2);
1802 : OSL_ENSURE(pBody, "Sm: NULL pointer!");
1803 : OSL_ENSURE(pBrace, "Sm: NULL pointer!");
1804 : OSL_ENSURE(pScript, "Sm: NULL pointer!");
1805 :
1806 36 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
1807 36 : aTmpDev.SetFont(GetFont());
1808 :
1809 36 : pBody->Arrange(aTmpDev, rFormat);
1810 :
1811 : // size is the same as for limits for this part
1812 36 : pScript->SetSize( Fraction( rFormat.GetRelSize(SIZ_LIMITS), 100 ) );
1813 : // braces are a bit taller than usually
1814 36 : pBrace ->SetSize( Fraction(3, 2) );
1815 :
1816 36 : long nItalicWidth = pBody->GetItalicWidth();
1817 36 : if (nItalicWidth > 0)
1818 36 : pBrace->AdaptToX(aTmpDev, nItalicWidth);
1819 :
1820 36 : pBrace ->Arrange(aTmpDev, rFormat);
1821 36 : pScript->Arrange(aTmpDev, rFormat);
1822 :
1823 : // determine the relative position and the distances between each other
1824 : RectPos eRectPos;
1825 36 : long nFontHeight = pBody->GetFont().GetSize().Height();
1826 36 : long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1827 36 : nDistScript = nFontHeight;
1828 36 : if (GetToken().eType == TOVERBRACE)
1829 : {
1830 18 : eRectPos = RP_TOP;
1831 18 : nDistBody = - nDistBody;
1832 18 : nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1833 : }
1834 : else // TUNDERBRACE
1835 : {
1836 18 : eRectPos = RP_BOTTOM;
1837 18 : nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1838 : }
1839 36 : nDistBody /= 100L;
1840 36 : nDistScript /= 100L;
1841 :
1842 36 : Point aPos = pBrace->AlignTo(*pBody, eRectPos, RHA_CENTER, RVA_BASELINE);
1843 36 : aPos.Y() += nDistBody;
1844 36 : pBrace->MoveTo(aPos);
1845 :
1846 36 : aPos = pScript->AlignTo(*pBrace, eRectPos, RHA_CENTER, RVA_BASELINE);
1847 36 : aPos.Y() += nDistScript;
1848 36 : pScript->MoveTo(aPos);
1849 :
1850 36 : SmRect::operator = (*pBody);
1851 36 : ExtendBy(*pBrace, RCP_THIS).ExtendBy(*pScript, RCP_THIS);
1852 36 : }
1853 :
1854 :
1855 : /**************************************************************************/
1856 :
1857 :
1858 164 : SmNode * SmOperNode::GetSymbol()
1859 : {
1860 164 : SmNode *pNode = GetSubNode(0);
1861 : OSL_ENSURE(pNode, "Sm: NULL pointer!");
1862 :
1863 164 : if (pNode->GetType() == NSUBSUP)
1864 161 : pNode = static_cast<SmSubSupNode *>(pNode)->GetBody();
1865 :
1866 : OSL_ENSURE(pNode, "Sm: NULL pointer!");
1867 164 : return pNode;
1868 : }
1869 :
1870 :
1871 162 : long SmOperNode::CalcSymbolHeight(const SmNode &rSymbol,
1872 : const SmFormat &rFormat) const
1873 : // returns the font height to be used for operator-symbol
1874 : {
1875 162 : long nHeight = GetFont().GetSize().Height();
1876 :
1877 162 : SmTokenType eTmpType = GetToken().eType;
1878 162 : if (eTmpType == TLIM || eTmpType == TLIMINF || eTmpType == TLIMSUP)
1879 15 : return nHeight;
1880 :
1881 147 : if (!rFormat.IsTextmode())
1882 : {
1883 : // set minimum size ()
1884 147 : nHeight += (nHeight * 20L) / 100L;
1885 :
1886 : nHeight += nHeight
1887 147 : * rFormat.GetDistance(DIS_OPERATORSIZE) / 100L;
1888 147 : nHeight = nHeight * 686L / 845L;
1889 : }
1890 :
1891 : // correct user-defined symbols to match height of sum from used font
1892 147 : if (rSymbol.GetToken().eType == TSPECIAL)
1893 0 : nHeight = nHeight * 845L / 686L;
1894 :
1895 147 : return nHeight;
1896 : }
1897 :
1898 :
1899 162 : void SmOperNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1900 : {
1901 162 : SmNode *pOper = GetSubNode(0);
1902 162 : SmNode *pBody = GetSubNode(1);
1903 :
1904 : OSL_ENSURE(pOper, "Sm: missing subnode");
1905 : OSL_ENSURE(pBody, "Sm: missing subnode");
1906 :
1907 162 : SmNode *pSymbol = GetSymbol();
1908 : pSymbol->SetSize(Fraction(CalcSymbolHeight(*pSymbol, rFormat),
1909 162 : pSymbol->GetFont().GetSize().Height()));
1910 :
1911 162 : pBody->Arrange(rDev, rFormat);
1912 162 : pOper->Arrange(rDev, rFormat);
1913 :
1914 162 : long nOrigHeight = GetFont().GetSize().Height(),
1915 : nDist = nOrigHeight
1916 162 : * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
1917 :
1918 162 : Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
1919 162 : aPos.X() -= nDist;
1920 162 : pOper->MoveTo(aPos);
1921 :
1922 162 : SmRect::operator = (*pBody);
1923 162 : ExtendBy(*pOper, RCP_THIS);
1924 162 : }
1925 :
1926 :
1927 : /**************************************************************************/
1928 :
1929 :
1930 0 : void SmAlignNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1931 : // set alignment within the entire subtree (including current node)
1932 : {
1933 : OSL_ENSURE(GetNumSubNodes() > 0, "Sm: missing subnode");
1934 :
1935 0 : SmNode *pNode = GetSubNode(0);
1936 :
1937 0 : RectHorAlign eHorAlign = RHA_CENTER;
1938 0 : switch (GetToken().eType)
1939 : {
1940 0 : case TALIGNL: eHorAlign = RHA_LEFT; break;
1941 0 : case TALIGNC: eHorAlign = RHA_CENTER; break;
1942 0 : case TALIGNR: eHorAlign = RHA_RIGHT; break;
1943 : default:
1944 0 : break;
1945 : }
1946 0 : SetRectHorAlign(eHorAlign);
1947 :
1948 0 : pNode->Arrange(rDev, rFormat);
1949 :
1950 0 : SmRect::operator = (pNode->GetRect());
1951 0 : }
1952 :
1953 :
1954 : /**************************************************************************/
1955 :
1956 :
1957 254 : void SmAttributNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
1958 : {
1959 254 : SmNode *pAttr = GetSubNode(0),
1960 254 : *pBody = GetSubNode(1);
1961 : OSL_ENSURE(pBody, "Sm: body missing");
1962 : OSL_ENSURE(pAttr, "Sm: attribute missing");
1963 :
1964 254 : pBody->Arrange(rDev, rFormat);
1965 :
1966 254 : if (GetScaleMode() == SCALE_WIDTH)
1967 144 : pAttr->AdaptToX(rDev, pBody->GetItalicWidth());
1968 254 : pAttr->Arrange(rDev, rFormat);
1969 :
1970 : // get relative position of attribute
1971 : RectVerAlign eVerAlign;
1972 254 : long nDist = 0;
1973 254 : switch (GetToken().eType)
1974 : { case TUNDERLINE :
1975 18 : eVerAlign = RVA_ATTRIBUT_LO;
1976 18 : break;
1977 : case TOVERSTRIKE :
1978 18 : eVerAlign = RVA_ATTRIBUT_MID;
1979 18 : break;
1980 : default :
1981 218 : eVerAlign = RVA_ATTRIBUT_HI;
1982 218 : if (pBody->GetType() == NATTRIBUT)
1983 0 : nDist = GetFont().GetSize().Height()
1984 0 : * rFormat.GetDistance(DIS_ORNAMENTSPACE) / 100L;
1985 : }
1986 254 : Point aPos = pAttr->AlignTo(*pBody, RP_ATTRIBUT, RHA_CENTER, eVerAlign);
1987 254 : aPos.Y() -= nDist;
1988 254 : pAttr->MoveTo(aPos);
1989 :
1990 254 : SmRect::operator = (*pBody);
1991 254 : ExtendBy(*pAttr, RCP_THIS, true);
1992 254 : }
1993 :
1994 0 : void SmFontNode::CreateTextFromNode(OUString &rText)
1995 : {
1996 0 : switch (GetToken().eType)
1997 : {
1998 : case TBOLD:
1999 0 : rText += "bold ";
2000 0 : break;
2001 : case TNBOLD:
2002 0 : rText += "nbold ";
2003 0 : break;
2004 : case TITALIC:
2005 0 : rText += "italic ";
2006 0 : break;
2007 : case TNITALIC:
2008 0 : rText += "nitalic ";
2009 0 : break;
2010 : case TPHANTOM:
2011 0 : rText += "phantom ";
2012 0 : break;
2013 : case TSIZE:
2014 : {
2015 0 : rText += "size ";
2016 0 : switch (nSizeType)
2017 : {
2018 : case FontSizeType::PLUS:
2019 0 : rText += "+";
2020 0 : break;
2021 : case FontSizeType::MINUS:
2022 0 : rText += "-";
2023 0 : break;
2024 : case FontSizeType::MULTIPLY:
2025 0 : rText += "*";
2026 0 : break;
2027 : case FontSizeType::DIVIDE:
2028 0 : rText += "/";
2029 0 : break;
2030 : case FontSizeType::ABSOLUT:
2031 : default:
2032 0 : break;
2033 : }
2034 0 : rText += ::rtl::math::doubleToUString(
2035 : static_cast<double>(aFontSize),
2036 : rtl_math_StringFormat_Automatic,
2037 0 : rtl_math_DecimalPlaces_Max, '.', true);
2038 0 : rText += " ";
2039 : }
2040 0 : break;
2041 : case TBLACK:
2042 0 : rText += "color black ";
2043 0 : break;
2044 : case TWHITE:
2045 0 : rText += "color white ";
2046 0 : break;
2047 : case TRED:
2048 0 : rText += "color red ";
2049 0 : break;
2050 : case TGREEN:
2051 0 : rText += "color green ";
2052 0 : break;
2053 : case TBLUE:
2054 0 : rText += "color blue ";
2055 0 : break;
2056 : case TCYAN:
2057 0 : rText += "color cyan ";
2058 0 : break;
2059 : case TMAGENTA:
2060 0 : rText += "color magenta ";
2061 0 : break;
2062 : case TYELLOW:
2063 0 : rText += "color yellow ";
2064 0 : break;
2065 : case TTEAL:
2066 0 : rText += "color teal";
2067 0 : break;
2068 : case TSILVER:
2069 0 : rText += "color silver";
2070 0 : break;
2071 : case TGRAY:
2072 0 : rText += "color gray";
2073 0 : break;
2074 : case TMAROON:
2075 0 : rText += "color maroon";
2076 0 : break;
2077 : case TPURPLE:
2078 0 : rText += "color purple";
2079 0 : break;
2080 : case TLIME:
2081 0 : rText += "color lime";
2082 0 : break;
2083 : case TOLIVE:
2084 0 : rText += "color olive";
2085 0 : break;
2086 : case TNAVY:
2087 0 : rText += "color navy";
2088 0 : break;
2089 : case TAQUA:
2090 0 : rText += "color aqua";
2091 0 : break;
2092 : case TFUCHSIA:
2093 0 : rText += "color fuchsia";
2094 0 : break;
2095 : case TSANS:
2096 0 : rText += "font sans ";
2097 0 : break;
2098 : case TSERIF:
2099 0 : rText += "font serif ";
2100 0 : break;
2101 : case TFIXED:
2102 0 : rText += "font fixed ";
2103 0 : break;
2104 : default:
2105 0 : break;
2106 : }
2107 0 : GetSubNode(1)->CreateTextFromNode(rText);
2108 0 : }
2109 :
2110 125 : void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2111 : {
2112 : //! prepare subnodes first
2113 125 : SmNode::Prepare(rFormat, rDocShell);
2114 :
2115 125 : int nFnt = -1;
2116 125 : switch (GetToken().eType)
2117 : {
2118 2 : case TFIXED: nFnt = FNT_FIXED; break;
2119 2 : case TSANS: nFnt = FNT_SANS; break;
2120 2 : case TSERIF: nFnt = FNT_SERIF; break;
2121 : default:
2122 119 : break;
2123 : }
2124 125 : if (nFnt != -1)
2125 6 : { GetFont() = rFormat.GetFont( sal::static_int_cast< sal_uInt16 >(nFnt) );
2126 6 : SetFont(GetFont());
2127 : }
2128 :
2129 : //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2130 : //! other font nodes (those with lower depth in the tree)
2131 125 : Flags() |= FLG_FONT;
2132 125 : }
2133 :
2134 91 : void SmFontNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2135 : {
2136 91 : SmNode *pNode = GetSubNode(1);
2137 : OSL_ENSURE(pNode, "Sm: missing subnode");
2138 :
2139 91 : switch (GetToken().eType)
2140 : { case TSIZE :
2141 66 : pNode->SetFontSize(aFontSize, nSizeType);
2142 66 : break;
2143 : case TSANS :
2144 : case TSERIF :
2145 : case TFIXED :
2146 0 : pNode->SetFont(GetFont());
2147 0 : break;
2148 1 : case TUNKNOWN : break; // no assertion on "font <?> <?>"
2149 :
2150 0 : case TPHANTOM : SetPhantom(true); break;
2151 0 : case TBOLD : SetAttribut(ATTR_BOLD); break;
2152 24 : case TITALIC : SetAttribut(ATTR_ITALIC); break;
2153 0 : case TNBOLD : ClearAttribut(ATTR_BOLD); break;
2154 0 : case TNITALIC : ClearAttribut(ATTR_ITALIC); break;
2155 :
2156 0 : case TBLACK : SetColor(Color(COL_BLACK)); break;
2157 0 : case TWHITE : SetColor(Color(COL_WHITE)); break;
2158 0 : case TRED : SetColor(Color(COL_LIGHTRED)); break;
2159 0 : case TGREEN : SetColor(Color(COL_GREEN)); break;
2160 0 : case TBLUE : SetColor(Color(COL_LIGHTBLUE)); break;
2161 0 : case TCYAN : SetColor(Color(COL_LIGHTCYAN)); break; // as in Calc
2162 0 : case TMAGENTA : SetColor(Color(COL_LIGHTMAGENTA)); break; // as in Calc
2163 0 : case TYELLOW : SetColor(Color(COL_YELLOW)); break;
2164 0 : case TTEAL : SetColor(Color(COL_CYAN)); break;
2165 0 : case TSILVER : SetColor(Color(COL_LIGHTGRAY)); break;
2166 0 : case TGRAY : SetColor(Color(COL_GRAY)); break;
2167 0 : case TMAROON : SetColor(Color(COL_RED)); break;
2168 0 : case TPURPLE : SetColor(Color(COL_MAGENTA)); break;
2169 0 : case TLIME : SetColor(Color(COL_LIGHTGREEN)); break;
2170 0 : case TOLIVE : SetColor(Color(COL_BROWN)); break;
2171 0 : case TNAVY : SetColor(Color(COL_BLUE)); break;
2172 0 : case TAQUA : SetColor(Color(COL_LIGHTCYAN)); break;
2173 0 : case TFUCHSIA : SetColor(Color(COL_LIGHTMAGENTA)); break;
2174 :
2175 : default:
2176 : SAL_WARN("starmath", "unknown case");
2177 : }
2178 :
2179 91 : pNode->Arrange(rDev, rFormat);
2180 :
2181 91 : SmRect::operator = (pNode->GetRect());
2182 91 : }
2183 :
2184 :
2185 66 : void SmFontNode::SetSizeParameter(const Fraction& rValue, FontSizeType Type)
2186 : {
2187 66 : nSizeType = Type;
2188 66 : aFontSize = rValue;
2189 66 : }
2190 :
2191 :
2192 : /**************************************************************************/
2193 :
2194 :
2195 34 : SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
2196 34 : : SmGraphicNode(NPOLYLINE, rNodeToken)
2197 : {
2198 34 : aPoly.SetSize(2);
2199 34 : nWidth = 0;
2200 34 : }
2201 :
2202 :
2203 34 : void SmPolyLineNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nNewWidth)
2204 : {
2205 34 : aToSize.Width() = nNewWidth;
2206 34 : }
2207 :
2208 :
2209 34 : void SmPolyLineNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nNewHeight)
2210 : {
2211 34 : GetFont().FreezeBorderWidth();
2212 34 : aToSize.Height() = nNewHeight;
2213 34 : }
2214 :
2215 :
2216 68 : void SmPolyLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2217 : {
2218 : //! some routines being called extract some info from the OutputDevice's
2219 : //! font (eg the space to be used for borders OR the font name(!!)).
2220 : //! Thus the font should reflect the needs and has to be set!
2221 68 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2222 68 : aTmpDev.SetFont(GetFont());
2223 :
2224 68 : long nBorderwidth = GetFont().GetBorderWidth();
2225 :
2226 : // create polygon using both endpoints
2227 : OSL_ENSURE(aPoly.GetSize() == 2, "Sm : wrong number of points");
2228 68 : Point aPointA, aPointB;
2229 68 : if (GetToken().eType == TWIDESLASH)
2230 : {
2231 34 : aPointA.X() = nBorderwidth;
2232 34 : aPointA.Y() = aToSize.Height() - nBorderwidth;
2233 34 : aPointB.X() = aToSize.Width() - nBorderwidth;
2234 34 : aPointB.Y() = nBorderwidth;
2235 : }
2236 : else
2237 : {
2238 : OSL_ENSURE(GetToken().eType == TWIDEBACKSLASH, "Sm : unexpected token");
2239 34 : aPointA.X() =
2240 34 : aPointA.Y() = nBorderwidth;
2241 34 : aPointB.X() = aToSize.Width() - nBorderwidth;
2242 34 : aPointB.Y() = aToSize.Height() - nBorderwidth;
2243 : }
2244 68 : aPoly.SetPoint(aPointA, 0);
2245 68 : aPoly.SetPoint(aPointB, 1);
2246 :
2247 68 : long nThick = GetFont().GetSize().Height()
2248 68 : * rFormat.GetDistance(DIS_STROKEWIDTH) / 100L;
2249 68 : nWidth = nThick + 2 * nBorderwidth;
2250 :
2251 68 : SmRect::operator = (SmRect(aToSize.Width(), aToSize.Height()));
2252 68 : }
2253 :
2254 :
2255 : /**************************************************************************/
2256 :
2257 78 : void SmRootSymbolNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2258 : {
2259 78 : nBodyWidth = nWidth;
2260 78 : }
2261 :
2262 :
2263 78 : void SmRootSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2264 : {
2265 : // some additional length so that the horizontal
2266 : // bar will be positioned above the argument
2267 78 : SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / 10L);
2268 78 : }
2269 :
2270 :
2271 : /**************************************************************************/
2272 :
2273 :
2274 0 : void SmDynIntegralSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2275 : {
2276 : static const long nFactor = 12L;
2277 :
2278 : // The new height equals (1 + nFactor) * oldHeight
2279 : // nFactor was chosen for keeping the integral sign from becoming too "fat".
2280 0 : SmMathSymbolNode::AdaptToY(rDev, nHeight + nHeight / nFactor);
2281 :
2282 : // keep the ratio
2283 0 : long nCurWidth = GetSize().Width();
2284 0 : SmMathSymbolNode::AdaptToX(rDev, nCurWidth + nCurWidth / nFactor);
2285 0 : }
2286 :
2287 :
2288 : /**************************************************************************/
2289 :
2290 :
2291 275 : void SmRectangleNode::AdaptToX(const OutputDevice &/*rDev*/, sal_uLong nWidth)
2292 : {
2293 275 : aToSize.Width() = nWidth;
2294 275 : }
2295 :
2296 :
2297 239 : void SmRectangleNode::AdaptToY(const OutputDevice &/*rDev*/, sal_uLong nHeight)
2298 : {
2299 239 : GetFont().FreezeBorderWidth();
2300 239 : aToSize.Height() = nHeight;
2301 239 : }
2302 :
2303 :
2304 275 : void SmRectangleNode::Arrange(const OutputDevice &rDev, const SmFormat &/*rFormat*/)
2305 : {
2306 275 : long nFontHeight = GetFont().GetSize().Height();
2307 275 : long nWidth = aToSize.Width(),
2308 275 : nHeight = aToSize.Height();
2309 275 : if (nHeight == 0)
2310 36 : nHeight = nFontHeight / 30;
2311 275 : if (nWidth == 0)
2312 0 : nWidth = nFontHeight / 3;
2313 :
2314 275 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2315 275 : aTmpDev.SetFont(GetFont());
2316 :
2317 : // add some borderspace
2318 275 : sal_uLong nTmpBorderWidth = GetFont().GetBorderWidth();
2319 275 : nHeight += 2 * nTmpBorderWidth;
2320 :
2321 : //! use this method in order to have 'SmRect::HasAlignInfo() == true'
2322 : //! and thus having the attribute-fences updated in 'SmRect::ExtendBy'
2323 275 : SmRect::operator = (SmRect(nWidth, nHeight));
2324 275 : }
2325 :
2326 :
2327 : /**************************************************************************/
2328 :
2329 :
2330 3692 : SmTextNode::SmTextNode( SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 nFontDescP )
2331 : : SmVisibleNode(eNodeType, rNodeToken)
2332 : , nFontDesc(nFontDescP)
2333 : , nSelectionStart(0)
2334 3692 : , nSelectionEnd(0)
2335 : {
2336 3692 : }
2337 :
2338 4940 : SmTextNode::SmTextNode( const SmToken &rNodeToken, sal_uInt16 nFontDescP )
2339 : : SmVisibleNode(NTEXT, rNodeToken)
2340 : , nFontDesc(nFontDescP)
2341 : , nSelectionStart(0)
2342 4940 : , nSelectionEnd(0)
2343 : {
2344 4940 : }
2345 :
2346 4925 : void SmTextNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2347 : {
2348 4925 : SmNode::Prepare(rFormat, rDocShell);
2349 :
2350 : // default setting for horizontal alignment of nodes with TTEXT
2351 : // content is as alignl (cannot be done in Arrange since it would
2352 : // override the settings made by an SmAlignNode before)
2353 4925 : if (TTEXT == GetToken().eType)
2354 102 : SetRectHorAlign( RHA_LEFT );
2355 :
2356 4925 : aText = GetToken().aText;
2357 4925 : GetFont() = rFormat.GetFont(GetFontDesc());
2358 :
2359 4925 : if (IsItalic( GetFont() ))
2360 3449 : Attributes() |= ATTR_ITALIC;
2361 4925 : if (IsBold( GetFont() ))
2362 32 : Attributes() |= ATTR_BOLD;
2363 :
2364 : // special handling for ':' where it is a token on it's own and is likely
2365 : // to be used for mathematical notations. (E.g. a:b = 2:3)
2366 : // In that case it should not be displayed in italic.
2367 4925 : if (GetToken().aText.getLength() == 1 && GetToken().aText[0] == ':')
2368 0 : Attributes() &= ~ATTR_ITALIC;
2369 4925 : };
2370 :
2371 :
2372 4268 : void SmTextNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2373 : {
2374 4268 : PrepareAttributes();
2375 :
2376 4268 : sal_uInt16 nSizeDesc = GetFontDesc() == FNT_FUNCTION ?
2377 4268 : SIZ_FUNCTION : SIZ_TEXT;
2378 4268 : GetFont() *= Fraction (rFormat.GetRelSize(nSizeDesc), 100);
2379 :
2380 4268 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2381 4268 : aTmpDev.SetFont(GetFont());
2382 :
2383 4268 : SmRect::operator = (SmRect(aTmpDev, &rFormat, aText, GetFont().GetBorderWidth()));
2384 4268 : }
2385 :
2386 9 : void SmTextNode::CreateTextFromNode(OUString &rText)
2387 : {
2388 9 : bool bQuoted=false;
2389 9 : if (GetToken().eType == TTEXT)
2390 : {
2391 0 : rText += "\"";
2392 0 : bQuoted=true;
2393 : }
2394 : else
2395 : {
2396 9 : SmParser aParseTest;
2397 9 : SmNode *pTable = aParseTest.Parse(GetToken().aText);
2398 9 : bQuoted=true;
2399 9 : if ( (pTable->GetType() == NTABLE) && (pTable->GetNumSubNodes() == 1) )
2400 : {
2401 9 : SmNode *pResult = pTable->GetSubNode(0);
2402 18 : if ( (pResult->GetType() == NLINE) &&
2403 9 : (pResult->GetNumSubNodes() == 1) )
2404 : {
2405 9 : pResult = pResult->GetSubNode(0);
2406 9 : if ( (pResult->GetType() == NEXPRESSION) &&
2407 0 : (pResult->GetNumSubNodes() == 1) )
2408 : {
2409 0 : pResult = pResult->GetSubNode(0);
2410 0 : if (pResult->GetType() == NTEXT)
2411 0 : bQuoted=false;
2412 : }
2413 : }
2414 : }
2415 9 : delete pTable;
2416 :
2417 9 : if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
2418 : {
2419 : //Search for existing functions and remove extraenous keyword
2420 0 : rText += "func ";
2421 : }
2422 9 : else if (bQuoted)
2423 9 : rText += "italic ";
2424 :
2425 9 : if (bQuoted)
2426 9 : rText += "\"";
2427 :
2428 : }
2429 :
2430 9 : rText += GetToken().aText;
2431 :
2432 9 : if (bQuoted)
2433 9 : rText += "\"";
2434 9 : rText += " ";
2435 9 : }
2436 :
2437 :
2438 0 : void SmTextNode::GetAccessibleText( OUStringBuffer &rText ) const
2439 : {
2440 0 : rText.append(aText);
2441 0 : }
2442 :
2443 13 : void SmTextNode::AdjustFontDesc()
2444 : {
2445 13 : if (GetToken().eType == TTEXT)
2446 0 : nFontDesc = FNT_TEXT;
2447 13 : else if(GetToken().eType == TFUNC)
2448 0 : nFontDesc = FNT_FUNCTION;
2449 : else {
2450 : SmTokenType nTok;
2451 13 : const SmTokenTableEntry *pEntry = SmParser::GetTokenTableEntry( aText );
2452 13 : if (pEntry && pEntry->nGroup == TGFUNCTION) {
2453 0 : nTok = pEntry->eType;
2454 0 : nFontDesc = FNT_FUNCTION;
2455 : } else {
2456 13 : sal_Unicode firstChar = aText[0];
2457 13 : if( ('0' <= firstChar && firstChar <= '9') || firstChar == '.' || firstChar == ',') {
2458 6 : nFontDesc = FNT_NUMBER;
2459 6 : nTok = TNUMBER;
2460 7 : } else if (aText.getLength() > 1) {
2461 0 : nFontDesc = FNT_VARIABLE;
2462 0 : nTok = TIDENT;
2463 : } else {
2464 7 : nFontDesc = FNT_VARIABLE;
2465 7 : nTok = TCHARACTER;
2466 : }
2467 : }
2468 13 : SmToken tok = GetToken();
2469 13 : tok.eType = nTok;
2470 13 : SetToken(tok);
2471 : }
2472 13 : }
2473 :
2474 900 : sal_Unicode SmTextNode::ConvertSymbolToUnicode(sal_Unicode nIn)
2475 : {
2476 : //Find the best match in accepted unicode for our private area symbols
2477 : static const sal_Unicode aStarMathPrivateToUnicode[] =
2478 : {
2479 : 0x2030, 0xF613, 0xF612, 0x002B, 0x003C, 0x003E, 0xE425, 0xE421, 0xE088, 0x2208,
2480 : 0x0192, 0x2026, 0x2192, 0x221A, 0x221A, 0x221A, 0xE090, 0x005E, 0x02C7, 0x02D8,
2481 : 0x00B4, 0x0060, 0x02DC, 0x00AF, 0x0362, 0xE099, 0xE09A, 0x20DB, 0xE09C, 0xE09D,
2482 : 0x0028, 0x0029, 0x2220, 0x22AF, 0xE0A2, 0xE0A3, 0xE0A4, 0xE0A5, 0xE0A6, 0xE0A7,
2483 : 0x002F, 0x005C, 0x274F, 0xE0AB, 0x0393, 0x0394, 0x0398, 0x039b, 0x039e, 0x03A0,
2484 : 0x03a3, 0x03a5, 0x03a6, 0x03a8, 0x03A9, 0x03B1, 0x03B2, 0x03b3, 0x03b4, 0x03b5,
2485 : 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
2486 : 0x03c0, 0x03c1, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03b5,
2487 : 0x03d1, 0x03d6, 0xE0D2, 0x03db, 0x2118, 0x2202, 0x2129, 0xE0D7, 0xE0D8, 0x22A4,
2488 : 0xE0DA, 0x2190, 0x2191, 0x2193
2489 : };
2490 900 : if ((nIn >= 0xE080) && (nIn <= 0xE0DD))
2491 0 : nIn = aStarMathPrivateToUnicode[nIn-0xE080];
2492 :
2493 : //For whatever unicode glyph that equation editor doesn't ship with that
2494 : //we have a possible match we can munge it to.
2495 900 : switch (nIn)
2496 : {
2497 : case 0x2223:
2498 0 : nIn = '|';
2499 0 : break;
2500 : default:
2501 900 : break;
2502 : }
2503 :
2504 900 : return nIn;
2505 : }
2506 :
2507 : /**************************************************************************/
2508 :
2509 1 : void SmMatrixNode::CreateTextFromNode(OUString &rText)
2510 : {
2511 1 : rText += "matrix {";
2512 4 : for (sal_uInt16 i = 0; i < nNumRows; i++)
2513 : {
2514 6 : for (sal_uInt16 j = 0; j < nNumCols; j++)
2515 : {
2516 3 : SmNode *pNode = GetSubNode(i * nNumCols + j);
2517 3 : if (pNode)
2518 3 : pNode->CreateTextFromNode(rText);
2519 3 : if (j != nNumCols-1)
2520 0 : rText += "# ";
2521 : }
2522 3 : if (i != nNumRows-1)
2523 2 : rText += "## ";
2524 : }
2525 1 : rText = comphelper::string::stripEnd(rText, ' ');
2526 1 : rText += "} ";
2527 1 : }
2528 :
2529 :
2530 20 : void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2531 : {
2532 : SmNode *pNode;
2533 : sal_uInt16 i, j;
2534 :
2535 : // initialize array that is to hold the maximum widths of all
2536 : // elements (subnodes) in that column.
2537 20 : std::vector<long> aColWidth(nNumCols);
2538 :
2539 : // arrange subnodes and calculate the aboves arrays contents
2540 20 : sal_uInt16 nNodes = GetNumSubNodes();
2541 98 : for (i = 0; i < nNodes; i++)
2542 : {
2543 78 : sal_uInt16 nIdx = nNodes - 1 - i;
2544 78 : if (NULL != (pNode = GetSubNode(nIdx)))
2545 : {
2546 78 : pNode->Arrange(rDev, rFormat);
2547 78 : int nCol = nIdx % nNumCols;
2548 78 : aColWidth[nCol] = std::max(aColWidth[nCol], pNode->GetItalicWidth());
2549 : }
2550 : }
2551 :
2552 : // norm distance from which the following two are calcutated
2553 20 : const long nNormDist = 3 * GetFont().GetSize().Height();
2554 :
2555 : // define horizontal and vertical minimal distances that separate
2556 : // the elements
2557 20 : long nHorDist = nNormDist * rFormat.GetDistance(DIS_MATRIXCOL) / 100L,
2558 20 : nVerDist = nNormDist * rFormat.GetDistance(DIS_MATRIXROW) / 100L;
2559 :
2560 : // build array that holds the leftmost position for each column
2561 40 : std::vector<long> aColLeft(nNumCols);
2562 20 : long nX = 0;
2563 58 : for (j = 0; j < nNumCols; j++)
2564 : {
2565 38 : aColLeft[j] = nX;
2566 38 : nX += aColWidth[j] + nHorDist;
2567 : }
2568 :
2569 20 : Point aPos, aDelta;
2570 20 : SmRect aLineRect;
2571 20 : SmRect::operator = (SmRect());
2572 62 : for (i = 0; i < nNumRows; i++)
2573 42 : { aLineRect = SmRect();
2574 120 : for (j = 0; j < nNumCols; j++)
2575 78 : { SmNode *pTmpNode = GetSubNode(i * nNumCols + j);
2576 : OSL_ENSURE(pTmpNode, "Sm: NULL pointer");
2577 :
2578 78 : const SmRect &rNodeRect = pTmpNode->GetRect();
2579 :
2580 : // align all baselines in that row if possible
2581 78 : aPos = rNodeRect.AlignTo(aLineRect, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
2582 78 : aPos.X() += nHorDist;
2583 :
2584 : // get horizontal alignment
2585 78 : const SmNode *pCoNode = pTmpNode->GetLeftMost();
2586 78 : RectHorAlign eHorAlign = pCoNode->GetRectHorAlign();
2587 :
2588 : // calculate horizontal position of element depending on column
2589 : // and horizontal alignment
2590 78 : switch (eHorAlign)
2591 : { case RHA_LEFT:
2592 0 : aPos.X() = rNodeRect.GetLeft() + aColLeft[j];
2593 0 : break;
2594 : case RHA_CENTER:
2595 78 : aPos.X() = rNodeRect.GetLeft() + aColLeft[j]
2596 78 : + aColWidth[j] / 2
2597 78 : - rNodeRect.GetItalicCenterX();
2598 78 : break;
2599 : case RHA_RIGHT:
2600 0 : aPos.X() = rNodeRect.GetLeft() + aColLeft[j]
2601 0 : + aColWidth[j] - rNodeRect.GetItalicWidth();
2602 0 : break;
2603 : }
2604 :
2605 78 : pTmpNode->MoveTo(aPos);
2606 78 : aLineRect.ExtendBy(rNodeRect, RCP_XOR);
2607 : }
2608 :
2609 42 : aPos = aLineRect.AlignTo(*this, RP_BOTTOM, RHA_CENTER, RVA_BASELINE);
2610 42 : aPos.Y() += nVerDist;
2611 :
2612 : // move 'aLineRect' and rectangles in that line to final position
2613 42 : aDelta.X() = 0; // since horizontal alignment is already done
2614 42 : aDelta.Y() = aPos.Y() - aLineRect.GetTop();
2615 42 : aLineRect.Move(aDelta);
2616 120 : for (j = 0; j < nNumCols; j++)
2617 78 : if (NULL != (pNode = GetSubNode(i * nNumCols + j)))
2618 78 : pNode->Move(aDelta);
2619 :
2620 42 : ExtendBy(aLineRect, RCP_NONE);
2621 20 : }
2622 20 : }
2623 :
2624 :
2625 25 : void SmMatrixNode::SetRowCol(sal_uInt16 nMatrixRows, sal_uInt16 nMatrixCols)
2626 : {
2627 25 : nNumRows = nMatrixRows;
2628 25 : nNumCols = nMatrixCols;
2629 25 : }
2630 :
2631 :
2632 2 : SmNode * SmMatrixNode::GetLeftMost()
2633 : {
2634 2 : return this;
2635 : }
2636 :
2637 :
2638 : /**************************************************************************/
2639 :
2640 :
2641 2766 : SmMathSymbolNode::SmMathSymbolNode(const SmToken &rNodeToken)
2642 2766 : : SmSpecialNode(NMATH, rNodeToken, FNT_MATH)
2643 : {
2644 2766 : sal_Unicode cChar = GetToken().cMathChar;
2645 2766 : if ((sal_Unicode) '\0' != cChar)
2646 2740 : SetText(OUString(cChar));
2647 2766 : }
2648 :
2649 144 : void SmMathSymbolNode::AdaptToX(const OutputDevice &rDev, sal_uLong nWidth)
2650 : {
2651 : // Since there is no function to do this, we try to approximate it:
2652 144 : Size aFntSize (GetFont().GetSize());
2653 :
2654 : //! however the result is a bit better with 'nWidth' as initial font width
2655 144 : aFntSize.Width() = nWidth;
2656 144 : GetFont().SetSize(aFntSize);
2657 :
2658 144 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2659 144 : aTmpDev.SetFont(GetFont());
2660 :
2661 : // get denominator of error factor for width
2662 144 : long nTmpBorderWidth = GetFont().GetBorderWidth();
2663 144 : long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetItalicWidth();
2664 :
2665 : // scale fontwidth with this error factor
2666 144 : aFntSize.Width() *= nWidth;
2667 144 : aFntSize.Width() /= nDenom ? nDenom : 1;
2668 :
2669 144 : GetFont().SetSize(aFntSize);
2670 144 : }
2671 :
2672 950 : void SmMathSymbolNode::AdaptToY(const OutputDevice &rDev, sal_uLong nHeight)
2673 : {
2674 950 : GetFont().FreezeBorderWidth();
2675 950 : Size aFntSize (GetFont().GetSize());
2676 :
2677 : // Since we only want to scale the height, we might have
2678 : // to determine the font width in order to keep it
2679 950 : if (aFntSize.Width() == 0)
2680 : {
2681 204 : OutputDevice &rDevNC = (OutputDevice &) rDev;
2682 204 : rDevNC.Push(PushFlags::FONT | PushFlags::MAPMODE);
2683 204 : rDevNC.SetFont(GetFont());
2684 204 : aFntSize.Width() = rDev.GetFontMetric().GetSize().Width();
2685 204 : rDevNC.Pop();
2686 : }
2687 : OSL_ENSURE(aFntSize.Width() != 0, "Sm: ");
2688 :
2689 : //! however the result is a bit better with 'nHeight' as initial
2690 : //! font height
2691 950 : aFntSize.Height() = nHeight;
2692 950 : GetFont().SetSize(aFntSize);
2693 :
2694 950 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2695 950 : aTmpDev.SetFont(GetFont());
2696 :
2697 : // get denominator of error factor for height
2698 950 : long nTmpBorderWidth = GetFont().GetBorderWidth();
2699 950 : long nDenom = SmRect(aTmpDev, NULL, GetText(), nTmpBorderWidth).GetHeight();
2700 :
2701 : // scale fontwidth with this error factor
2702 950 : aFntSize.Height() *= nHeight;
2703 950 : aFntSize.Height() /= nDenom ? nDenom : 1;
2704 :
2705 950 : GetFont().SetSize(aFntSize);
2706 950 : }
2707 :
2708 :
2709 2868 : void SmMathSymbolNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2710 : {
2711 2868 : SmNode::Prepare(rFormat, rDocShell);
2712 :
2713 2868 : GetFont() = rFormat.GetFont(GetFontDesc());
2714 : // use same font size as is used for variables
2715 2868 : GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2716 :
2717 : OSL_ENSURE(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL ||
2718 : GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE,
2719 : "wrong charset for character from StarMath/OpenSymbol font");
2720 :
2721 2868 : Flags() |= FLG_FONT | FLG_ITALIC;
2722 2868 : };
2723 :
2724 :
2725 2429 : void SmMathSymbolNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2726 : {
2727 2429 : const OUString &rText = GetText();
2728 :
2729 2429 : if (rText.isEmpty() || rText[0] == '\0')
2730 24 : { SmRect::operator = (SmRect());
2731 2453 : return;
2732 : }
2733 :
2734 2405 : PrepareAttributes();
2735 :
2736 2405 : GetFont() *= Fraction (rFormat.GetRelSize(SIZ_TEXT), 100);
2737 :
2738 2405 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2739 2405 : aTmpDev.SetFont(GetFont());
2740 :
2741 2405 : SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
2742 : }
2743 :
2744 6 : void SmMathSymbolNode::CreateTextFromNode(OUString &rText)
2745 : {
2746 6 : OUString sStr;
2747 6 : MathType::LookupChar(GetToken().cMathChar, sStr);
2748 6 : rText += sStr;
2749 6 : }
2750 :
2751 0 : void SmRectangleNode::CreateTextFromNode(OUString &rText)
2752 : {
2753 0 : switch (GetToken().eType)
2754 : {
2755 : case TUNDERLINE:
2756 0 : rText += "underline ";
2757 0 : break;
2758 : case TOVERLINE:
2759 0 : rText += "overline ";
2760 0 : break;
2761 : case TOVERSTRIKE:
2762 0 : rText += "overstrike ";
2763 0 : break;
2764 : default:
2765 0 : break;
2766 : }
2767 0 : }
2768 :
2769 0 : void SmAttributNode::CreateTextFromNode(OUString &rText)
2770 : {
2771 : SmNode *pNode;
2772 0 : sal_uInt16 nSize = GetNumSubNodes();
2773 : OSL_ENSURE(nSize == 2, "Node missing members");
2774 0 : rText += "{";
2775 0 : sal_Unicode nLast=0;
2776 0 : if (NULL != (pNode = GetSubNode(0)))
2777 : {
2778 0 : OUString aStr;
2779 0 : pNode->CreateTextFromNode(aStr);
2780 0 : if (aStr.getLength() > 1)
2781 0 : rText += aStr;
2782 : else
2783 : {
2784 0 : nLast = aStr[0];
2785 0 : switch (nLast)
2786 : {
2787 : case MS_BAR: // MACRON
2788 0 : rText += "overline ";
2789 0 : break;
2790 : case MS_DOT: // DOT ABOVE
2791 0 : rText += "dot ";
2792 0 : break;
2793 : case 0x2dc: // SMALL TILDE
2794 0 : rText += "widetilde ";
2795 0 : break;
2796 : case MS_DDOT: // DIAERESIS
2797 0 : rText += "ddot ";
2798 0 : break;
2799 : case 0xE082:
2800 0 : break;
2801 : case 0xE09B:
2802 : case MS_DDDOT: // COMBINING THREE DOTS ABOVE
2803 0 : rText += "dddot ";
2804 0 : break;
2805 : case MS_ACUTE: // ACUTE ACCENT
2806 : case MS_COMBACUTE: // COMBINING ACUTE ACCENT
2807 0 : rText += "acute ";
2808 0 : break;
2809 : case MS_GRAVE: // GRAVE ACCENT
2810 : case MS_COMBGRAVE: // COMBINING GRAVE ACCENT
2811 0 : rText += "grave ";
2812 0 : break;
2813 : case MS_CHECK: // CARON
2814 : case MS_COMBCHECK: // COMBINING CARON
2815 0 : rText += "check ";
2816 0 : break;
2817 : case MS_BREVE: // BREVE
2818 : case MS_COMBBREVE: // COMBINING BREVE
2819 0 : rText += "breve ";
2820 0 : break;
2821 : case MS_CIRCLE: // RING ABOVE
2822 : case MS_COMBCIRCLE: // COMBINING RING ABOVE
2823 0 : rText += "circle ";
2824 0 : break;
2825 : case MS_RIGHTARROW: // RIGHTWARDS ARROW
2826 : case MS_VEC: // COMBINING RIGHT ARROW ABOVE
2827 0 : rText += "vec ";
2828 0 : break;
2829 : case MS_TILDE: // TILDE
2830 : case MS_COMBTILDE: // COMBINING TILDE
2831 0 : rText += "tilde ";
2832 0 : break;
2833 : case MS_HAT: // CIRCUMFLEX ACCENT
2834 : case MS_COMBHAT: // COMBINING CIRCUMFLEX ACCENT
2835 0 : rText += "hat ";
2836 0 : break;
2837 : case MS_COMBBAR: // COMBINING MACRON
2838 0 : rText += "bar ";
2839 0 : break;
2840 : default:
2841 0 : rText += OUString( nLast );
2842 0 : break;
2843 : }
2844 0 : }
2845 : }
2846 :
2847 0 : if (nSize == 2)
2848 0 : if (NULL != (pNode = GetSubNode(1)))
2849 0 : pNode->CreateTextFromNode(rText);
2850 :
2851 0 : rText = comphelper::string::stripEnd(rText, ' ');
2852 :
2853 0 : if (nLast == 0xE082)
2854 0 : rText += " overbrace {}";
2855 :
2856 0 : rText += "} ";
2857 0 : }
2858 :
2859 : /**************************************************************************/
2860 :
2861 3692 : static bool lcl_IsFromGreekSymbolSet( const OUString &rTokenText )
2862 : {
2863 3692 : bool bRes = false;
2864 :
2865 : // valid symbol name needs to have a '%' at pos 0 and at least an additional char
2866 3692 : if (rTokenText.getLength() > 2 && rTokenText[0] == (sal_Unicode)'%')
2867 : {
2868 131 : OUString aName( rTokenText.copy(1) );
2869 131 : SmSym *pSymbol = SM_MOD()->GetSymbolManager().GetSymbolByName( aName );
2870 131 : if (pSymbol && GetExportSymbolSetName(pSymbol->GetSymbolSetName()) == "Greek")
2871 106 : bRes = true;
2872 : }
2873 :
2874 3692 : return bRes;
2875 : }
2876 :
2877 :
2878 3561 : SmSpecialNode::SmSpecialNode(SmNodeType eNodeType, const SmToken &rNodeToken, sal_uInt16 _nFontDesc) :
2879 3561 : SmTextNode(eNodeType, rNodeToken, _nFontDesc)
2880 : {
2881 3561 : bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2882 3561 : }
2883 :
2884 :
2885 131 : SmSpecialNode::SmSpecialNode(const SmToken &rNodeToken) :
2886 131 : SmTextNode(NSPECIAL, rNodeToken, FNT_MATH) // default Font isn't always correct!
2887 : {
2888 131 : bIsFromGreekSymbolSet = lcl_IsFromGreekSymbolSet( rNodeToken.aText );
2889 131 : }
2890 :
2891 :
2892 131 : void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2893 : {
2894 131 : SmNode::Prepare(rFormat, rDocShell);
2895 :
2896 : const SmSym *pSym;
2897 131 : SmModule *pp = SM_MOD();
2898 :
2899 131 : OUString aName(GetToken().aText.copy(1));
2900 131 : if (NULL != (pSym = pp->GetSymbolManager().GetSymbolByName( aName )))
2901 : {
2902 130 : sal_UCS4 cChar = pSym->GetCharacter();
2903 130 : OUString aTmp( &cChar, 1 );
2904 130 : SetText( aTmp );
2905 130 : GetFont() = pSym->GetFace();
2906 : }
2907 : else
2908 : {
2909 1 : SetText( GetToken().aText );
2910 1 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
2911 : }
2912 : // use same font size as is used for variables
2913 131 : GetFont().SetSize( rFormat.GetFont( FNT_VARIABLE ).GetSize() );
2914 :
2915 : // Actually only WEIGHT_NORMAL and WEIGHT_BOLD should occur... However, the sms-file also
2916 : // contains e.g. 'WEIGHT_ULTRALIGHT'. Consequently, compare here with '>' instead of '!='.
2917 : // (In the long term the necessity for 'PrepareAttribut' and thus also for this here should be dropped)
2918 :
2919 : //! see also SmFontStyles::GetStyleName
2920 131 : if (IsItalic( GetFont() ))
2921 1 : SetAttribut(ATTR_ITALIC);
2922 131 : if (IsBold( GetFont() ))
2923 0 : SetAttribut(ATTR_BOLD);
2924 :
2925 131 : Flags() |= FLG_FONT;
2926 :
2927 131 : if (bIsFromGreekSymbolSet)
2928 : {
2929 : OSL_ENSURE( GetText().getLength() == 1, "a symbol should only consist of 1 char!" );
2930 106 : bool bItalic = false;
2931 106 : sal_Int16 nStyle = rFormat.GetGreekCharStyle();
2932 : OSL_ENSURE( nStyle >= 0 && nStyle <= 2, "unexpected value for GreekCharStyle" );
2933 106 : if (nStyle == 1)
2934 0 : bItalic = true;
2935 106 : else if (nStyle == 2)
2936 : {
2937 0 : const OUString& rTmp(GetText());
2938 0 : if (rTmp.isEmpty())
2939 : {
2940 : static const sal_Unicode cUppercaseAlpha = 0x0391;
2941 : static const sal_Unicode cUppercaseOmega = 0x03A9;
2942 0 : sal_Unicode cChar = rTmp[0];
2943 : // uppercase letters should be straight and lowercase letters italic
2944 0 : bItalic = !(cUppercaseAlpha <= cChar && cChar <= cUppercaseOmega);
2945 : }
2946 : }
2947 :
2948 106 : if (bItalic)
2949 0 : Attributes() |= ATTR_ITALIC;
2950 : else
2951 106 : Attributes() &= ~ATTR_ITALIC;
2952 131 : }
2953 131 : };
2954 :
2955 :
2956 0 : void SmSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2957 : {
2958 0 : PrepareAttributes();
2959 :
2960 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2961 0 : aTmpDev.SetFont(GetFont());
2962 :
2963 0 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
2964 0 : }
2965 :
2966 : /**************************************************************************/
2967 :
2968 :
2969 0 : void SmGlyphSpecialNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2970 : {
2971 0 : PrepareAttributes();
2972 :
2973 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2974 0 : aTmpDev.SetFont(GetFont());
2975 :
2976 0 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(),
2977 0 : GetFont().GetBorderWidth()).AsGlyphRect());
2978 0 : }
2979 :
2980 :
2981 : /**************************************************************************/
2982 :
2983 :
2984 654 : void SmPlaceNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2985 : {
2986 654 : SmNode::Prepare(rFormat, rDocShell);
2987 :
2988 654 : GetFont().SetColor(COL_GRAY);
2989 654 : Flags() |= FLG_COLOR | FLG_FONT | FLG_ITALIC;
2990 654 : };
2991 :
2992 :
2993 654 : void SmPlaceNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2994 : {
2995 654 : PrepareAttributes();
2996 :
2997 654 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
2998 654 : aTmpDev.SetFont(GetFont());
2999 :
3000 654 : SmRect::operator = (SmRect(aTmpDev, &rFormat, GetText(), GetFont().GetBorderWidth()));
3001 654 : }
3002 :
3003 :
3004 : /**************************************************************************/
3005 :
3006 :
3007 27 : void SmErrorNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3008 : {
3009 27 : SmNode::Prepare(rFormat, rDocShell);
3010 :
3011 27 : GetFont().SetColor(COL_RED);
3012 27 : Flags() |= FLG_VISIBLE | FLG_BOLD | FLG_ITALIC
3013 27 : | FLG_COLOR | FLG_FONT | FLG_SIZE;
3014 27 : }
3015 :
3016 :
3017 27 : void SmErrorNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3018 : {
3019 27 : PrepareAttributes();
3020 :
3021 27 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3022 27 : aTmpDev.SetFont(GetFont());
3023 :
3024 27 : const OUString &rText = GetText();
3025 27 : SmRect::operator = (SmRect(aTmpDev, &rFormat, rText, GetFont().GetBorderWidth()));
3026 27 : }
3027 :
3028 :
3029 : /**************************************************************************/
3030 :
3031 :
3032 4 : void SmBlankNode::IncreaseBy(const SmToken &rToken)
3033 : {
3034 4 : switch(rToken.eType)
3035 : {
3036 2 : case TBLANK: nNum += 4; break;
3037 2 : case TSBLANK: nNum += 1; break;
3038 : default:
3039 0 : break;
3040 : }
3041 4 : }
3042 :
3043 :
3044 4 : void SmBlankNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
3045 : {
3046 4 : SmNode::Prepare(rFormat, rDocShell);
3047 :
3048 : // Here it need/should not be the StarMath font, so that for the character
3049 : // used in Arrange a normal (non-clipped) rectangle is generated
3050 4 : GetFont() = rFormat.GetFont(FNT_VARIABLE);
3051 :
3052 4 : Flags() |= FLG_FONT | FLG_BOLD | FLG_ITALIC;
3053 4 : }
3054 :
3055 :
3056 0 : void SmBlankNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
3057 : {
3058 0 : SmTmpDevice aTmpDev ((OutputDevice &) rDev, true);
3059 0 : aTmpDev.SetFont(GetFont());
3060 :
3061 : // make distance depend on the font height
3062 : // (so that it increases when scaling (e.g. size *2 {a ~ b})
3063 0 : long nDist = GetFont().GetSize().Height() / 10L,
3064 0 : nSpace = nNum * nDist;
3065 :
3066 : // get a SmRect with Baseline and all the bells and whistles
3067 : SmRect::operator = (SmRect(aTmpDev, &rFormat, OUString(' '),
3068 0 : GetFont().GetBorderWidth()));
3069 :
3070 : // and resize it to the requested size
3071 0 : SetItalicSpaces(0, 0);
3072 0 : SetWidth(nSpace);
3073 0 : }
3074 :
3075 : /**************************************************************************/
3076 : //Implementation of all accept methods for SmVisitor
3077 :
3078 0 : void SmNode::Accept(SmVisitor*){
3079 : //This method is only implemented to avoid making SmNode abstract because an
3080 : //obscure copy constructor is used... I can't find it's implementation, and
3081 : //don't want to figure out how to fix it... If you want to, just delete this
3082 : //method, making SmNode abstract, and see where you can an problem with that.
3083 : SAL_WARN("starmath", "SmNode should not be visitable!");
3084 0 : }
3085 :
3086 5156 : void SmTableNode::Accept(SmVisitor* pVisitor) {
3087 5156 : pVisitor->Visit(this);
3088 5156 : }
3089 :
3090 2650 : void SmBraceNode::Accept(SmVisitor* pVisitor) {
3091 2650 : pVisitor->Visit(this);
3092 2650 : }
3093 :
3094 2642 : void SmBracebodyNode::Accept(SmVisitor* pVisitor) {
3095 2642 : pVisitor->Visit(this);
3096 2642 : }
3097 :
3098 960 : void SmOperNode::Accept(SmVisitor* pVisitor) {
3099 960 : pVisitor->Visit(this);
3100 960 : }
3101 :
3102 28 : void SmAlignNode::Accept(SmVisitor* pVisitor) {
3103 28 : pVisitor->Visit(this);
3104 28 : }
3105 :
3106 1503 : void SmAttributNode::Accept(SmVisitor* pVisitor) {
3107 1503 : pVisitor->Visit(this);
3108 1503 : }
3109 :
3110 84 : void SmFontNode::Accept(SmVisitor* pVisitor) {
3111 84 : pVisitor->Visit(this);
3112 84 : }
3113 :
3114 553 : void SmUnHorNode::Accept(SmVisitor* pVisitor) {
3115 553 : pVisitor->Visit(this);
3116 553 : }
3117 :
3118 4207 : void SmBinHorNode::Accept(SmVisitor* pVisitor) {
3119 4207 : pVisitor->Visit(this);
3120 4207 : }
3121 :
3122 1308 : void SmBinVerNode::Accept(SmVisitor* pVisitor) {
3123 1308 : pVisitor->Visit(this);
3124 1308 : }
3125 :
3126 64 : void SmBinDiagonalNode::Accept(SmVisitor* pVisitor) {
3127 64 : pVisitor->Visit(this);
3128 64 : }
3129 :
3130 4043 : void SmSubSupNode::Accept(SmVisitor* pVisitor) {
3131 4043 : pVisitor->Visit(this);
3132 4043 : }
3133 :
3134 110 : void SmMatrixNode::Accept(SmVisitor* pVisitor) {
3135 110 : pVisitor->Visit(this);
3136 110 : }
3137 :
3138 1576 : void SmPlaceNode::Accept(SmVisitor* pVisitor) {
3139 1576 : pVisitor->Visit(this);
3140 1576 : }
3141 :
3142 24476 : void SmTextNode::Accept(SmVisitor* pVisitor) {
3143 24476 : pVisitor->Visit(this);
3144 24476 : }
3145 :
3146 262 : void SmSpecialNode::Accept(SmVisitor* pVisitor) {
3147 262 : pVisitor->Visit(this);
3148 262 : }
3149 :
3150 0 : void SmGlyphSpecialNode::Accept(SmVisitor* pVisitor) {
3151 0 : pVisitor->Visit(this);
3152 0 : }
3153 :
3154 13005 : void SmMathSymbolNode::Accept(SmVisitor* pVisitor) {
3155 13005 : pVisitor->Visit(this);
3156 13005 : }
3157 :
3158 8 : void SmBlankNode::Accept(SmVisitor* pVisitor) {
3159 8 : pVisitor->Visit(this);
3160 8 : }
3161 :
3162 148 : void SmErrorNode::Accept(SmVisitor* pVisitor) {
3163 148 : pVisitor->Visit(this);
3164 148 : }
3165 :
3166 4593 : void SmLineNode::Accept(SmVisitor* pVisitor) {
3167 4593 : pVisitor->Visit(this);
3168 4593 : }
3169 :
3170 3760 : void SmExpressionNode::Accept(SmVisitor* pVisitor) {
3171 3760 : pVisitor->Visit(this);
3172 3760 : }
3173 :
3174 64 : void SmPolyLineNode::Accept(SmVisitor* pVisitor) {
3175 64 : pVisitor->Visit(this);
3176 64 : }
3177 :
3178 450 : void SmRootNode::Accept(SmVisitor* pVisitor) {
3179 450 : pVisitor->Visit(this);
3180 450 : }
3181 :
3182 446 : void SmRootSymbolNode::Accept(SmVisitor* pVisitor) {
3183 446 : pVisitor->Visit(this);
3184 446 : }
3185 :
3186 0 : void SmDynIntegralNode::Accept(SmVisitor* pVisitor) {
3187 0 : pVisitor->Visit(this);
3188 0 : }
3189 :
3190 :
3191 0 : void SmDynIntegralSymbolNode::Accept(SmVisitor* pVisitor) {
3192 0 : pVisitor->Visit(this);
3193 0 : }
3194 :
3195 1483 : void SmRectangleNode::Accept(SmVisitor* pVisitor) {
3196 1483 : pVisitor->Visit(this);
3197 1483 : }
3198 :
3199 212 : void SmVerticalBraceNode::Accept(SmVisitor* pVisitor) {
3200 212 : pVisitor->Visit(this);
3201 254 : }
3202 :
3203 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|