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