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