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