Branch data 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 : : #include <osl/diagnose.h>
21 : : #include <vcl/svapp.hxx>
22 : : #include <vcl/wrkwin.hxx>
23 : : #include <vcl/virdev.hxx>
24 : :
25 : :
26 : : #include "rect.hxx"
27 : : #include "types.hxx"
28 : : #include "utility.hxx"
29 : : #include "smmod.hxx"
30 : :
31 : :
32 : : ////////////////////////////////////////////////////////////////////////////////
33 : :
34 : :
35 : : // '\0' terminated Array with symbol, which should be treat as letters in
36 : : // StarMath Font, (to get a normal (non-clipped) SmRect in contrast to the
37 : : // other operators and symbols).
38 : : static xub_Unicode const aMathAlpha[] =
39 : : {
40 : : MS_ALEPH, MS_IM, MS_RE,
41 : : MS_WP, xub_Unicode(0xE070), MS_EMPTYSET,
42 : : xub_Unicode(0x2113), xub_Unicode(0xE0D6), xub_Unicode(0x2107),
43 : : xub_Unicode(0x2127), xub_Unicode(0x210A), MS_HBAR,
44 : : MS_LAMBDABAR, MS_SETN, MS_SETZ,
45 : : MS_SETQ, MS_SETR, MS_SETC,
46 : : xub_Unicode(0x2373), xub_Unicode(0xE0A5), xub_Unicode(0x2112),
47 : : xub_Unicode(0x2130), xub_Unicode(0x2131),
48 : : xub_Unicode('\0')
49 : : };
50 : :
51 : 6388 : bool SmIsMathAlpha(const rtl::OUString &rText)
52 : : // true iff symbol (from StarMath Font) should be treated as letter
53 : : {
54 [ + + ]: 6388 : if (rText.isEmpty())
55 : 18 : return false;
56 : :
57 : : OSL_ENSURE(rText.getLength() == 1, "Sm : string must be exactly one character long");
58 : 6370 : xub_Unicode cChar = rText[0];
59 : :
60 : : // is it a greek symbol?
61 [ # # ][ - + ]: 6370 : if (xub_Unicode(0xE0AC) <= cChar && cChar <= xub_Unicode(0xE0D4))
62 : 0 : return true;
63 : : else
64 : : {
65 : : // appears it in 'aMathAlpha'?
66 : 6370 : const xub_Unicode *pChar = aMathAlpha;
67 [ + + ][ + - ]: 152880 : while (*pChar && *pChar != cChar)
[ + + ]
68 : 146510 : pChar++;
69 : 6388 : return *pChar != xub_Unicode('\0');
70 : : }
71 : : }
72 : :
73 : :
74 : : ////////////////////////////////////////
75 : : //
76 : : // SmRect members
77 : : //
78 : :
79 : :
80 : 28088 : SmRect::SmRect()
81 : : // constructs empty rectangle at (0, 0) with width and height 0.
82 : : {
83 : : OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
84 : : OSL_ENSURE(aSize == Size(0, 0), "Sm: ooops...");
85 : :
86 : 28088 : bHasBaseline = bHasAlignInfo = false;
87 : : nBaseline = nAlignT = nAlignM = nAlignB =
88 : : nGlyphTop = nGlyphBottom =
89 : : nItalicLeftSpace = nItalicRightSpace =
90 : 28088 : nLoAttrFence = nHiAttrFence = 0;
91 : 28088 : nBorderWidth = 0;
92 : 28088 : }
93 : :
94 : :
95 : 31546 : SmRect::SmRect(const SmRect &rRect)
96 : : : aTopLeft(rRect.aTopLeft),
97 : 31546 : aSize(rRect.aSize)
98 : : {
99 : 31546 : bHasBaseline = rRect.bHasBaseline;
100 : 31546 : nBaseline = rRect.nBaseline;
101 : 31546 : nAlignT = rRect.nAlignT;
102 : 31546 : nAlignM = rRect.nAlignM;
103 : 31546 : nAlignB = rRect.nAlignB;
104 : 31546 : nGlyphTop = rRect.nGlyphTop;
105 : 31546 : nGlyphBottom = rRect.nGlyphBottom;
106 : 31546 : nHiAttrFence = rRect.nHiAttrFence;
107 : 31546 : nLoAttrFence = rRect.nLoAttrFence;
108 : 31546 : bHasAlignInfo = rRect.bHasAlignInfo;
109 : 31546 : nItalicLeftSpace = rRect.nItalicLeftSpace;
110 : 31546 : nItalicRightSpace = rRect.nItalicRightSpace;
111 : 31546 : nBorderWidth = rRect.nBorderWidth;
112 : 31546 : }
113 : :
114 : :
115 : 180 : void SmRect::CopyAlignInfo(const SmRect &rRect)
116 : : {
117 : 180 : nBaseline = rRect.nBaseline;
118 : 180 : bHasBaseline = rRect.bHasBaseline;
119 : 180 : nAlignT = rRect.nAlignT;
120 : 180 : nAlignM = rRect.nAlignM;
121 : 180 : nAlignB = rRect.nAlignB;
122 : 180 : bHasAlignInfo = rRect.bHasAlignInfo;
123 : 180 : nLoAttrFence = rRect.nLoAttrFence;
124 : 180 : nHiAttrFence = rRect.nHiAttrFence;
125 : 180 : }
126 : :
127 : :
128 : 14130 : void SmRect::BuildRect(const OutputDevice &rDev, const SmFormat *pFormat,
129 : : const rtl::OUString &rText, sal_uInt16 nBorder)
130 : : {
131 : : OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: Ooops...");
132 : :
133 [ + - ][ + - ]: 14130 : aSize = Size(rDev.GetTextWidth(rText), rDev.GetTextHeight());
[ + - ][ + - ]
134 : :
135 [ + - ]: 14130 : const FontMetric aFM (rDev.GetFontMetric());
136 [ + - ][ + - ]: 14130 : bool bIsMath = aFM.GetName().EqualsIgnoreCaseAscii( FONTNAME_MATH );
137 [ + + ][ + - ]: 14130 : bool bAllowSmaller = bIsMath && !SmIsMathAlpha(rText);
138 [ + - ]: 14130 : const long nFontHeight = rDev.GetFont().GetSize().Height();
139 : :
140 : 14130 : nBorderWidth = nBorder;
141 : 14130 : bHasAlignInfo = true;
142 : 14130 : bHasBaseline = true;
143 [ + - ]: 14130 : nBaseline = aFM.GetAscent();
144 : 14130 : nAlignT = nBaseline - nFontHeight * 750L / 1000L;
145 : 14130 : nAlignM = nBaseline - nFontHeight * 121L / 422L;
146 : : // that's where the horizontal bars of '+', '-', ... are
147 : : // (1/3 of ascent over baseline)
148 : : // (121 = 1/3 of 12pt ascent, 422 = 12pt fontheight)
149 : 14130 : nAlignB = nBaseline;
150 : :
151 : : // workaround for printer fonts with very small (possible 0 or even
152 : : // negative(!)) leading
153 [ + - ][ + + ]: 14130 : if (aFM.GetIntLeading() < 5 && rDev.GetOutDevType() == OUTDEV_PRINTER)
[ + - ][ + + ]
154 : : {
155 [ + - ]: 16 : OutputDevice *pWindow = Application::GetDefaultDevice();
156 : :
157 [ + - ]: 16 : pWindow->Push(PUSH_MAPMODE | PUSH_FONT);
158 : :
159 [ + - ]: 16 : pWindow->SetMapMode(rDev.GetMapMode());
160 [ + - ][ + - ]: 16 : pWindow->SetFont(rDev.GetFontMetric());
[ + - ]
161 : :
162 [ + - ][ + - ]: 16 : long nDelta = pWindow->GetFontMetric().GetIntLeading();
[ + - ]
163 [ + - ]: 16 : if (nDelta == 0)
164 : : { // this value approx. fits a Leading of 80 at a
165 : : // Fontheight of 422 (12pt)
166 : 16 : nDelta = nFontHeight * 8L / 43;
167 : : }
168 [ + - ]: 16 : SetTop(GetTop() - nDelta);
169 : :
170 [ + - ]: 16 : pWindow->Pop();
171 : : }
172 : :
173 : : // get GlyphBoundRect
174 [ + - ]: 14130 : Rectangle aGlyphRect;
175 : : #if OSL_DEBUG_LEVEL > 1
176 : : bool bSuccess =
177 : : #endif
178 [ + - ]: 14130 : SmGetGlyphBoundRect(rDev, rText, aGlyphRect);
179 : : #if OSL_DEBUG_LEVEL > 1
180 : : if (!bSuccess)
181 : : {
182 : : OSL_FAIL( "Sm : Ooops... (fehlt evtl. der Font?)");
183 : : }
184 : : #endif
185 : :
186 : 14130 : nItalicLeftSpace = GetLeft() - aGlyphRect.Left() + nBorderWidth;
187 [ + - ]: 14130 : nItalicRightSpace = aGlyphRect.Right() - GetRight() + nBorderWidth;
188 [ + + ][ + + ]: 14130 : if (nItalicLeftSpace < 0 && !bAllowSmaller)
189 : 1118 : nItalicLeftSpace = 0;
190 [ + + ][ + + ]: 14130 : if (nItalicRightSpace < 0 && !bAllowSmaller)
191 : 1824 : nItalicRightSpace = 0;
192 : :
193 : 14130 : long nDist = 0;
194 [ + + ]: 14130 : if (pFormat)
195 [ + - ]: 12150 : nDist = (rDev.GetFont().GetSize().Height()
196 : 12150 : * pFormat->GetDistance(DIS_ORNAMENTSIZE)) / 100L;
197 : :
198 : 14130 : nHiAttrFence = aGlyphRect.TopLeft().Y() - 1 - nBorderWidth - nDist;
199 [ + - ]: 14130 : nLoAttrFence = SmFromTo(GetAlignB(), GetBottom(), 0.0);
200 : :
201 : 14130 : nGlyphTop = aGlyphRect.Top() - nBorderWidth;
202 : 14130 : nGlyphBottom = aGlyphRect.Bottom() + nBorderWidth;
203 : :
204 [ + + ]: 14130 : if (bAllowSmaller)
205 : : {
206 : : // for symbols and operators from the StarMath Font
207 : : // we adjust upper and lower margin of the symbol
208 [ + - ]: 6388 : SetTop(nGlyphTop);
209 : 6388 : SetBottom(nGlyphBottom);
210 : : }
211 : :
212 [ + + ]: 14130 : if (nHiAttrFence < GetTop())
213 : 6424 : nHiAttrFence = GetTop();
214 : :
215 [ + - ][ + + ]: 14130 : if (nLoAttrFence > GetBottom())
216 [ + - ]: 1756 : nLoAttrFence = GetBottom();
217 : :
218 : : OSL_ENSURE(rText.isEmpty() || !IsEmpty(),
219 [ + - ]: 14130 : "Sm: empty rectangle created");
220 : 14130 : }
221 : :
222 : :
223 : 14130 : void SmRect::Init(const OutputDevice &rDev, const SmFormat *pFormat,
224 : : const rtl::OUString &rText, sal_uInt16 nEBorderWidth)
225 : : // get rectangle fitting for drawing 'rText' on OutputDevice 'rDev'
226 : : {
227 : 14130 : BuildRect(rDev, pFormat, rText, nEBorderWidth);
228 : 14130 : }
229 : :
230 : :
231 : 14130 : SmRect::SmRect(const OutputDevice &rDev, const SmFormat *pFormat,
232 : 14130 : const rtl::OUString &rText, long nEBorderWidth)
233 : : {
234 : : OSL_ENSURE( nEBorderWidth >= 0, "BorderWidth is negative" );
235 [ - + ]: 14130 : if (nEBorderWidth < 0)
236 : 0 : nEBorderWidth = 0;
237 : 14130 : Init(rDev, pFormat, rText, (sal_uInt16) nEBorderWidth);
238 : 14130 : }
239 : :
240 : :
241 : 2174 : SmRect::SmRect(long nWidth, long nHeight)
242 : : // this constructor should never be used for anything textlike because
243 : : // it will not provide useful values for baseline, AlignT and AlignB!
244 : : // It's purpose is to get a 'SmRect' for the horizontal line in fractions
245 : : // as used in 'SmBinVerNode'.
246 : 2174 : : aSize(nWidth, nHeight)
247 : : {
248 : : OSL_ENSURE(aTopLeft == Point(0, 0), "Sm: ooops...");
249 : :
250 : 2174 : bHasBaseline = false;
251 : 2174 : bHasAlignInfo = true;
252 : 2174 : nBaseline = 0;
253 : 2174 : nAlignT = GetTop();
254 : 2174 : nAlignB = GetBottom();
255 : 2174 : nAlignM = (nAlignT + nAlignB) / 2; // this is the default
256 : 2174 : nItalicLeftSpace = nItalicRightSpace = 0;
257 : 2174 : nGlyphTop = nHiAttrFence = GetTop();
258 : 2174 : nGlyphBottom = nLoAttrFence = GetBottom();
259 : 2174 : nBorderWidth = 0;
260 : 2174 : }
261 : :
262 : :
263 : 13190 : void SmRect::SetLeft(long nLeft)
264 : : {
265 [ + + ]: 13190 : if (nLeft <= GetRight())
266 : 13082 : { aSize.Width() = GetRight() - nLeft + 1;
267 : 13082 : aTopLeft.X() = nLeft;
268 : : }
269 : 13190 : }
270 : :
271 : :
272 : 13190 : void SmRect::SetRight(long nRight)
273 : : {
274 [ + - ]: 13190 : if (nRight >= GetLeft())
275 : 13190 : aSize.Width() = nRight - GetLeft() + 1;
276 : 13190 : }
277 : :
278 : :
279 : 19596 : void SmRect::SetBottom(long nBottom)
280 : : {
281 [ + + ]: 19596 : if (nBottom >= GetTop())
282 : 19578 : aSize.Height() = nBottom - GetTop() + 1;
283 : 19596 : }
284 : :
285 : :
286 : 19594 : void SmRect::SetTop(long nTop)
287 : : {
288 [ + + ]: 19594 : if (nTop <= GetBottom())
289 : 19558 : { aSize.Height() = GetBottom() - nTop + 1;
290 : 19558 : aTopLeft.Y() = nTop;
291 : : }
292 : 19594 : }
293 : :
294 : :
295 : 67626 : void SmRect::Move(const Point &rPosition)
296 : : // move rectangle by position 'rPosition'.
297 : : {
298 : 67626 : aTopLeft += rPosition;
299 : :
300 : 67626 : long nDelta = rPosition.Y();
301 : 67626 : nBaseline += nDelta;
302 : 67626 : nAlignT += nDelta;
303 : 67626 : nAlignM += nDelta;
304 : 67626 : nAlignB += nDelta;
305 : 67626 : nGlyphTop += nDelta;
306 : 67626 : nGlyphBottom += nDelta;
307 : 67626 : nHiAttrFence += nDelta;
308 : 67626 : nLoAttrFence += nDelta;
309 : 67626 : }
310 : :
311 : :
312 : 13788 : const Point SmRect::AlignTo(const SmRect &rRect, RectPos ePos,
313 : : RectHorAlign eHor, RectVerAlign eVer) const
314 : 13788 : { Point aPos (GetTopLeft());
315 : : // will become the topleft point of the new rectangle position
316 : :
317 : : // set horizontal or vertical new rectangle position depending on
318 : : // 'ePos' is one of 'RP_LEFT', 'RP_RIGHT' or 'RP_TOP', 'RP_BOTTOM'
319 [ + + + + : 13788 : switch (ePos)
+ - ]
320 : : { case RP_LEFT :
321 : 1338 : aPos.X() = rRect.GetItalicLeft() - GetItalicRightSpace()
322 : 1338 : - GetWidth();
323 : 1338 : break;
324 : : case RP_RIGHT :
325 : 8472 : aPos.X() = rRect.GetItalicRight() + 1 + GetItalicLeftSpace();
326 : 8472 : break;
327 : : case RP_TOP :
328 : 792 : aPos.Y() = rRect.GetTop() - GetHeight();
329 : 792 : break;
330 : : case RP_BOTTOM :
331 : 2678 : aPos.Y() = rRect.GetBottom() + 1;
332 : 2678 : break;
333 : : case RP_ATTRIBUT :
334 : 508 : aPos.X() = rRect.GetItalicCenterX() - GetItalicWidth() / 2
335 : 508 : + GetItalicLeftSpace();
336 : 508 : break;
337 : : default :
338 : : OSL_FAIL("Sm: unknown case");
339 : : }
340 : :
341 : : // check if horizontal position is already set
342 [ + + ][ + + ]: 13788 : if (ePos == RP_LEFT || ePos == RP_RIGHT || ePos == RP_ATTRIBUT)
[ + + ]
343 : : // correct error in current vertical position
344 [ + + + + : 10318 : switch (eVer)
+ + + +
- ]
345 : : { case RVA_TOP :
346 : 738 : aPos.Y() += rRect.GetAlignT() - GetAlignT();
347 : 738 : break;
348 : : case RVA_MID :
349 : 258 : aPos.Y() += rRect.GetAlignM() - GetAlignM();
350 : 258 : break;
351 : : case RVA_BASELINE :
352 : : // align baselines if possible else align mid's
353 [ + + ][ + + ]: 6834 : if (HasBaseline() && rRect.HasBaseline())
[ + + ]
354 : 5988 : aPos.Y() += rRect.GetBaseline() - GetBaseline();
355 : : else
356 : 846 : aPos.Y() += rRect.GetAlignM() - GetAlignM();
357 : 6834 : break;
358 : : case RVA_BOTTOM :
359 : 288 : aPos.Y() += rRect.GetAlignB() - GetAlignB();
360 : 288 : break;
361 : : case RVA_CENTERY :
362 : 1692 : aPos.Y() += rRect.GetCenterY() - GetCenterY();
363 : 1692 : break;
364 : : case RVA_ATTRIBUT_HI:
365 : 436 : aPos.Y() += rRect.GetHiAttrFence() - GetBottom();
366 : 436 : break;
367 : : case RVA_ATTRIBUT_MID :
368 : 72 : aPos.Y() += SmFromTo(rRect.GetAlignB(), rRect.GetAlignT(), 0.4)
369 : 36 : - GetCenterY();
370 : 36 : break;
371 : : case RVA_ATTRIBUT_LO :
372 : 36 : aPos.Y() += rRect.GetLoAttrFence() - GetTop();
373 : 36 : break;
374 : : default :
375 : : OSL_FAIL("Sm: unknown case");
376 : : }
377 : :
378 : : // check if vertical position is already set
379 [ + + ][ + + ]: 13788 : if (ePos == RP_TOP || ePos == RP_BOTTOM)
380 : : // correct error in current horizontal position
381 [ - + + - ]: 3470 : switch (eHor)
382 : : { case RHA_LEFT :
383 : 0 : aPos.X() += rRect.GetItalicLeft() - GetItalicLeft();
384 : 0 : break;
385 : : case RHA_CENTER :
386 : 3360 : aPos.X() += rRect.GetItalicCenterX() - GetItalicCenterX();
387 : 3360 : break;
388 : : case RHA_RIGHT :
389 : 110 : aPos.X() += rRect.GetItalicRight() - GetItalicRight();
390 : 110 : break;
391 : : default :
392 : : OSL_FAIL("Sm: unknown case");
393 : : }
394 : :
395 : 13788 : return aPos;
396 : : }
397 : :
398 : :
399 : 13608 : SmRect & SmRect::Union(const SmRect &rRect)
400 : : // rectangle union of current one with 'rRect'. The result is to be the
401 : : // smallest rectangles that covers the space of both rectangles.
402 : : // (empty rectangles cover no space)
403 : : //! Italic correction is NOT taken into account here!
404 : : {
405 [ + + ]: 13608 : if (rRect.IsEmpty())
406 : 418 : return *this;
407 : :
408 : 13190 : long nL = rRect.GetLeft(),
409 : 13190 : nR = rRect.GetRight(),
410 : 13190 : nT = rRect.GetTop(),
411 : 13190 : nB = rRect.GetBottom(),
412 : 13190 : nGT = rRect.nGlyphTop,
413 : 13190 : nGB = rRect.nGlyphBottom;
414 [ + + ]: 13190 : if (!IsEmpty())
415 : : { long nTmp;
416 : :
417 [ + + ]: 13010 : if ((nTmp = GetLeft()) < nL)
418 : 10628 : nL = nTmp;
419 [ + + ]: 13010 : if ((nTmp = GetRight()) > nR)
420 : 3338 : nR = nTmp;
421 [ + + ]: 13010 : if ((nTmp = GetTop()) < nT)
422 : 6538 : nT = nTmp;
423 [ + + ]: 13010 : if ((nTmp = GetBottom()) > nB)
424 : 4562 : nB = nTmp;
425 [ + + ]: 13010 : if ((nTmp = nGlyphTop) < nGT)
426 : 7096 : nGT = nTmp;
427 [ + + ]: 13010 : if ((nTmp = nGlyphBottom) > nGB)
428 : 5264 : nGB = nTmp;
429 : : }
430 : :
431 : 13190 : SetLeft(nL);
432 : 13190 : SetRight(nR);
433 : 13190 : SetTop(nT);
434 : 13190 : SetBottom(nB);
435 : 13190 : nGlyphTop = nGT;
436 : 13190 : nGlyphBottom = nGB;
437 : :
438 : 13608 : return *this;
439 : : }
440 : :
441 : :
442 : 13608 : SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode)
443 : : // let current rectangle be the union of itself and 'rRect'
444 : : // (the smallest rectangle surrounding both). Also adapt values for
445 : : // 'AlignT', 'AlignM', 'AlignB', baseline and italic-spaces.
446 : : // The baseline is set according to 'eCopyMode'.
447 : : // If one of the rectangles has no relevant info the other one is copied.
448 : : {
449 : : // get some values used for (italic) spaces adaption
450 : : // ! (need to be done before changing current SmRect) !
451 : 13608 : long nL = Min(GetItalicLeft(), rRect.GetItalicLeft()),
452 : 13608 : nR = Max(GetItalicRight(), rRect.GetItalicRight());
453 : :
454 : 13608 : Union(rRect);
455 : :
456 : 13608 : SetItalicSpaces(GetLeft() - nL, nR - GetRight());
457 : :
458 [ + + ]: 13608 : if (!HasAlignInfo())
459 : 180 : CopyAlignInfo(rRect);
460 [ + + ]: 13428 : else if (rRect.HasAlignInfo())
461 : 13410 : { nAlignT = Min(GetAlignT(), rRect.GetAlignT());
462 : 13410 : nAlignB = Max(GetAlignB(), rRect.GetAlignB());
463 : 13410 : nHiAttrFence = Min(GetHiAttrFence(), rRect.GetHiAttrFence());
464 : 13410 : nLoAttrFence = Max(GetLoAttrFence(), rRect.GetLoAttrFence());
465 : : OSL_ENSURE(HasAlignInfo(), "Sm: ooops...");
466 : :
467 [ + + + + : 13410 : switch (eCopyMode)
- ]
468 : : { case RCP_THIS:
469 : : // already done
470 : 4186 : break;
471 : : case RCP_ARG:
472 : 1436 : CopyMBL(rRect);
473 : 1436 : break;
474 : : case RCP_NONE:
475 : 1386 : ClearBaseline();
476 : 1386 : nAlignM = (nAlignT + nAlignB) / 2;
477 : 1386 : break;
478 : : case RCP_XOR:
479 [ + + ]: 6402 : if (!HasBaseline())
480 : 270 : CopyMBL(rRect);
481 : 13410 : break;
482 : : default :
483 : : OSL_FAIL("Sm: unknown case");
484 : : }
485 : : }
486 : :
487 : 13608 : return *this;
488 : : }
489 : :
490 : :
491 : 504 : SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
492 : : long nNewAlignM)
493 : : // as 'ExtendBy' but sets AlignM value to 'nNewAlignM'.
494 : : // (this version will be used in 'SmBinVerNode' to provide means to
495 : : // align eg "{a over b} over c" correctly where AlignM should not
496 : : // be (AlignT + AlignB) / 2)
497 : : {
498 : : OSL_ENSURE(HasAlignInfo(), "Sm: no align info");
499 : :
500 : 504 : ExtendBy(rRect, eCopyMode);
501 : 504 : nAlignM = nNewAlignM;
502 : :
503 : 504 : return *this;
504 : : }
505 : :
506 : :
507 : 2038 : SmRect & SmRect::ExtendBy(const SmRect &rRect, RectCopyMBL eCopyMode,
508 : : bool bKeepVerAlignParams)
509 : : // as 'ExtendBy' but keeps original values for AlignT, -M and -B and
510 : : // baseline.
511 : : // (this is used in 'SmSupSubNode' where the sub-/supscripts shouldn't
512 : : // be allowed to modify these values.)
513 : : {
514 : 2038 : long nOldAlignT = GetAlignT(),
515 : 2038 : nOldAlignM = GetAlignM(),
516 : 2038 : nOldAlignB = GetAlignB(),
517 : 2038 : nOldBaseline = nBaseline; //! depends not on 'HasBaseline'
518 : 2038 : bool bOldHasAlignInfo = HasAlignInfo();
519 : :
520 : 2038 : ExtendBy(rRect, eCopyMode);
521 : :
522 [ + - ]: 2038 : if (bKeepVerAlignParams)
523 : 2038 : { nAlignT = nOldAlignT;
524 : 2038 : nAlignM = nOldAlignM;
525 : 2038 : nAlignB = nOldAlignB;
526 : 2038 : nBaseline = nOldBaseline;
527 : 2038 : bHasAlignInfo = bOldHasAlignInfo;
528 : : }
529 : :
530 : 2038 : return *this;
531 : : }
532 : :
533 : :
534 : 0 : long SmRect::OrientedDist(const Point &rPoint) const
535 : : // return oriented distance of rPoint to the current rectangle,
536 : : // especially the return value is <= 0 iff the point is inside the
537 : : // rectangle.
538 : : // For simplicity the maximum-norm is used.
539 : : {
540 [ # # ]: 0 : bool bIsInside = IsInsideItalicRect(rPoint);
541 : :
542 : : // build reference point to define the distance
543 : 0 : Point aRef;
544 [ # # ]: 0 : if (bIsInside)
545 [ # # ][ # # ]: 0 : { Point aIC (GetItalicCenterX(), GetCenterY());
546 : :
547 [ # # ][ # # ]: 0 : aRef.X() = rPoint.X() >= aIC.X() ? GetItalicRight() : GetItalicLeft();
548 [ # # ][ # # ]: 0 : aRef.Y() = rPoint.Y() >= aIC.Y() ? GetBottom() : GetTop();
549 : : }
550 : : else
551 : : {
552 : : // x-coordinate
553 [ # # ][ # # ]: 0 : if (rPoint.X() > GetItalicRight())
554 [ # # ]: 0 : aRef.X() = GetItalicRight();
555 [ # # ]: 0 : else if (rPoint.X() < GetItalicLeft())
556 : 0 : aRef.X() = GetItalicLeft();
557 : : else
558 : 0 : aRef.X() = rPoint.X();
559 : : // y-coordinate
560 [ # # ][ # # ]: 0 : if (rPoint.Y() > GetBottom())
561 [ # # ]: 0 : aRef.Y() = GetBottom();
562 [ # # ]: 0 : else if (rPoint.Y() < GetTop())
563 : 0 : aRef.Y() = GetTop();
564 : : else
565 : 0 : aRef.Y() = rPoint.Y();
566 : : }
567 : :
568 : : // build distance vector
569 : 0 : Point aDist (aRef - rPoint);
570 : :
571 : 0 : long nAbsX = labs(aDist.X()),
572 : 0 : nAbsY = labs(aDist.Y());
573 : :
574 [ # # ]: 0 : return bIsInside ? - Min(nAbsX, nAbsY) : Max (nAbsX, nAbsY);
575 : : }
576 : :
577 : :
578 : 0 : bool SmRect::IsInsideRect(const Point &rPoint) const
579 : : {
580 : 0 : return rPoint.Y() >= GetTop()
581 : 0 : && rPoint.Y() <= GetBottom()
582 : 0 : && rPoint.X() >= GetLeft()
583 [ # # ][ # # : 0 : && rPoint.X() <= GetRight();
# # # # ]
584 : : }
585 : :
586 : :
587 : 0 : bool SmRect::IsInsideItalicRect(const Point &rPoint) const
588 : : {
589 : 0 : return rPoint.Y() >= GetTop()
590 : 0 : && rPoint.Y() <= GetBottom()
591 : 0 : && rPoint.X() >= GetItalicLeft()
592 [ # # ][ # # : 0 : && rPoint.X() <= GetItalicRight();
# # # # ]
593 : : }
594 : :
595 : 0 : SmRect SmRect::AsGlyphRect() const
596 : : {
597 : 0 : SmRect aRect (*this);
598 : 0 : aRect.SetTop(nGlyphTop);
599 : 0 : aRect.SetBottom(nGlyphBottom);
600 : 0 : return aRect;
601 : : }
602 : :
603 : 14130 : bool SmGetGlyphBoundRect(const OutputDevice &rDev,
604 : : const rtl::OUString &rText, Rectangle &rRect)
605 : : // basically the same as 'GetTextBoundRect' (in class 'OutputDevice')
606 : : // but with a string as argument.
607 : : {
608 : : // handle special case first
609 [ + + ]: 14130 : if (rText.isEmpty())
610 : : {
611 : 18 : rRect.SetEmpty();
612 : 18 : return true;
613 : : }
614 : :
615 : : // get a device where 'OutputDevice::GetTextBoundRect' will be successful
616 : : OutputDevice *pGlyphDev;
617 [ + + ]: 14112 : if (rDev.GetOutDevType() != OUTDEV_PRINTER)
618 : 13932 : pGlyphDev = (OutputDevice *) &rDev;
619 : : else
620 : : {
621 : : // since we format for the printer (where GetTextBoundRect will fail)
622 : : // we need a virtual device here.
623 [ + - ][ + - ]: 180 : pGlyphDev = &SM_MOD()->GetDefaultVirtualDev();
624 : : }
625 : :
626 [ + - ]: 14112 : const FontMetric aDevFM (rDev.GetFontMetric());
627 : :
628 [ + - ]: 14112 : pGlyphDev->Push(PUSH_FONT | PUSH_MAPMODE);
629 [ + - ]: 14112 : Font aFnt(rDev.GetFont());
630 [ + - ]: 14112 : aFnt.SetAlign(ALIGN_TOP);
631 : :
632 : : // use scale factor when calling GetTextBoundRect to counter
633 : : // negative effects from antialiasing which may otherwise result
634 : : // in significant incorrect bounding rectangles for some charcters.
635 [ + - ]: 14112 : Size aFntSize = aFnt.GetSize();
636 : :
637 : : // Workaround to avoid HUGE font sizes and resulting problems
638 : 14112 : long nScaleFactor = 1;
639 [ + + ]: 14238 : while( aFntSize.Height() > 2000 * nScaleFactor )
640 : 126 : nScaleFactor *= 2;
641 : :
642 [ + - ]: 14112 : aFnt.SetSize( Size( aFntSize.Width() / nScaleFactor, aFntSize.Height() / nScaleFactor ) );
643 [ + - ]: 14112 : pGlyphDev->SetFont(aFnt);
644 : :
645 [ + - ][ + - ]: 14112 : long nTextWidth = rDev.GetTextWidth(rText);
[ + - ]
646 : 14112 : Point aPoint;
647 [ + - ][ + - ]: 14112 : Rectangle aResult (aPoint, Size(nTextWidth, rDev.GetTextHeight())),
648 [ + - ]: 14112 : aTmp;
649 : :
650 [ + - ][ + - ]: 14112 : bool bSuccess = pGlyphDev->GetTextBoundRect(aTmp, rText, 0, 0);
[ + - ]
651 : : OSL_ENSURE( bSuccess, "GetTextBoundRect failed" );
652 : :
653 : :
654 [ + - ][ + + ]: 14112 : if (!aTmp.IsEmpty())
655 : : {
656 : 11700 : aResult = Rectangle(aTmp.Left() * nScaleFactor, aTmp.Top() * nScaleFactor,
657 [ + - ]: 23400 : aTmp.Right() * nScaleFactor, aTmp.Bottom() * nScaleFactor);
658 [ + + ]: 11700 : if (&rDev != pGlyphDev) /* only when rDev is a printer... */
659 : : {
660 [ + - ][ + - ]: 180 : long nGDTextWidth = pGlyphDev->GetTextWidth(rText);
[ + - ]
661 [ + + ][ + - ]: 180 : if (nGDTextWidth != 0 &&
662 : : nTextWidth != nGDTextWidth)
663 : : {
664 : 176 : aResult.Right() *= nTextWidth;
665 : 176 : aResult.Right() /= nGDTextWidth * nScaleFactor;
666 : : }
667 : : }
668 : : }
669 : :
670 : : // move rectangle to match possibly different baselines
671 : : // (because of different devices)
672 [ + - ][ + - ]: 14112 : long nDelta = aDevFM.GetAscent() - pGlyphDev->GetFontMetric().GetAscent() * nScaleFactor;
[ + - ][ + - ]
673 [ + - ]: 14112 : aResult.Move(0, nDelta);
674 : :
675 [ + - ]: 14112 : pGlyphDev->Pop();
676 : :
677 : 14112 : rRect = aResult;
678 [ + - ][ + - ]: 14130 : return bSuccess;
679 : : }
680 : :
681 : :
682 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|