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