Backed out changeset 496886cb30a5 (bug 1867152) for bc failures on browser_user_input...
[gecko.git] / layout / generic / nsTextPaintStyle.cpp
blobc425ab785b1bf284cb37962e62da1e43ef885aac
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTextPaintStyle.h"
9 #include "nsCSSColorUtils.h"
10 #include "nsCSSRendering.h"
11 #include "nsFrameSelection.h"
12 #include "nsLayoutUtils.h"
13 #include "nsTextFrame.h"
14 #include "nsStyleConsts.h"
16 #include "mozilla/LookAndFeel.h"
18 using namespace mozilla;
19 using namespace mozilla::dom;
21 static nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB) {
22 if (colorA == colorB) {
23 nscolor res;
24 res = NS_RGB(NS_GET_R(colorA) ^ 0xff, NS_GET_G(colorA) ^ 0xff,
25 NS_GET_B(colorA) ^ 0xff);
26 return res;
28 return colorA;
31 nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
32 : mFrame(aFrame),
33 mPresContext(aFrame->PresContext()),
34 mInitCommonColors(false),
35 mInitSelectionColorsAndShadow(false),
36 mResolveColors(true),
37 mSelectionTextColor(NS_RGBA(0, 0, 0, 0)),
38 mSelectionBGColor(NS_RGBA(0, 0, 0, 0)),
39 mSufficientContrast(0),
40 mFrameBackgroundColor(NS_RGBA(0, 0, 0, 0)),
41 mSystemFieldForegroundColor(NS_RGBA(0, 0, 0, 0)),
42 mSystemFieldBackgroundColor(NS_RGBA(0, 0, 0, 0)) {
43 for (uint32_t i = 0; i < ArrayLength(mSelectionStyle); i++)
44 mSelectionStyle[i].mInit = false;
47 bool nsTextPaintStyle::EnsureSufficientContrast(nscolor* aForeColor,
48 nscolor* aBackColor) {
49 InitCommonColors();
51 const bool sameAsForeground = *aForeColor == NS_SAME_AS_FOREGROUND_COLOR;
52 if (sameAsForeground) {
53 *aForeColor = GetTextColor();
56 // If the combination of selection background color and frame background color
57 // has sufficient contrast, don't exchange the selection colors.
59 // Note we use a different threshold here: mSufficientContrast is for contrast
60 // between text and background colors, but since we're diffing two
61 // backgrounds, we don't need that much contrast. We match the heuristic from
62 // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE_BG and use 20% of mSufficientContrast.
63 const int32_t minLuminosityDifferenceForBackground = mSufficientContrast / 5;
64 const int32_t backLuminosityDifference =
65 NS_LUMINOSITY_DIFFERENCE(*aBackColor, mFrameBackgroundColor);
66 if (backLuminosityDifference >= minLuminosityDifferenceForBackground) {
67 return false;
70 // Otherwise, we should use the higher-contrast color for the selection
71 // background color.
73 // For NS_SAME_AS_FOREGROUND_COLOR we only do this if the background is
74 // totally indistinguishable, that is, if the luminosity difference is 0.
75 if (sameAsForeground && backLuminosityDifference) {
76 return false;
79 int32_t foreLuminosityDifference =
80 NS_LUMINOSITY_DIFFERENCE(*aForeColor, mFrameBackgroundColor);
81 if (backLuminosityDifference < foreLuminosityDifference) {
82 std::swap(*aForeColor, *aBackColor);
83 // Ensure foreground color is opaque to guarantee contrast.
84 *aForeColor = NS_RGB(NS_GET_R(*aForeColor), NS_GET_G(*aForeColor),
85 NS_GET_B(*aForeColor));
86 return true;
88 return false;
91 nscolor nsTextPaintStyle::GetTextColor() {
92 if (mFrame->IsInSVGTextSubtree()) {
93 if (!mResolveColors) {
94 return NS_SAME_AS_FOREGROUND_COLOR;
97 const nsStyleSVG* style = mFrame->StyleSVG();
98 switch (style->mFill.kind.tag) {
99 case StyleSVGPaintKind::Tag::None:
100 return NS_RGBA(0, 0, 0, 0);
101 case StyleSVGPaintKind::Tag::Color:
102 return nsLayoutUtils::GetColor(mFrame, &nsStyleSVG::mFill);
103 default:
104 NS_ERROR("cannot resolve SVG paint to nscolor");
105 return NS_RGBA(0, 0, 0, 255);
109 return nsLayoutUtils::GetColor(mFrame, &nsStyleText::mWebkitTextFillColor);
112 bool nsTextPaintStyle::GetSelectionColors(nscolor* aForeColor,
113 nscolor* aBackColor) {
114 NS_ASSERTION(aForeColor, "aForeColor is null");
115 NS_ASSERTION(aBackColor, "aBackColor is null");
117 if (!InitSelectionColorsAndShadow()) {
118 return false;
121 *aForeColor = mSelectionTextColor;
122 *aBackColor = mSelectionBGColor;
123 return true;
126 void nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
127 nscolor* aBackColor) {
128 NS_ASSERTION(aForeColor, "aForeColor is null");
129 NS_ASSERTION(aBackColor, "aBackColor is null");
131 const nsFrameSelection* frameSelection = mFrame->GetConstFrameSelection();
132 const Selection* selection =
133 frameSelection->GetSelection(SelectionType::eFind);
134 const SelectionCustomColors* customColors = nullptr;
135 if (selection) {
136 customColors = selection->GetCustomColors();
139 if (!customColors) {
140 nscolor backColor = LookAndFeel::Color(
141 LookAndFeel::ColorID::TextHighlightBackground, mFrame);
142 nscolor foreColor = LookAndFeel::Color(
143 LookAndFeel::ColorID::TextHighlightForeground, mFrame);
144 EnsureSufficientContrast(&foreColor, &backColor);
145 *aForeColor = foreColor;
146 *aBackColor = backColor;
147 return;
150 if (customColors->mForegroundColor && customColors->mBackgroundColor) {
151 nscolor foreColor = *customColors->mForegroundColor;
152 nscolor backColor = *customColors->mBackgroundColor;
154 if (EnsureSufficientContrast(&foreColor, &backColor) &&
155 customColors->mAltForegroundColor &&
156 customColors->mAltBackgroundColor) {
157 foreColor = *customColors->mAltForegroundColor;
158 backColor = *customColors->mAltBackgroundColor;
161 *aForeColor = foreColor;
162 *aBackColor = backColor;
163 return;
166 InitCommonColors();
168 if (customColors->mBackgroundColor) {
169 // !mForegroundColor means "currentColor"; the current color of the text.
170 nscolor foreColor = GetTextColor();
171 nscolor backColor = *customColors->mBackgroundColor;
173 int32_t luminosityDifference =
174 NS_LUMINOSITY_DIFFERENCE(foreColor, backColor);
176 if (mSufficientContrast > luminosityDifference &&
177 customColors->mAltBackgroundColor) {
178 int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
179 foreColor, *customColors->mAltBackgroundColor);
181 if (luminosityDifference < altLuminosityDifference) {
182 backColor = *customColors->mAltBackgroundColor;
186 *aForeColor = foreColor;
187 *aBackColor = backColor;
188 return;
191 if (customColors->mForegroundColor) {
192 nscolor foreColor = *customColors->mForegroundColor;
193 // !mBackgroundColor means "transparent"; the current color of the
194 // background.
196 int32_t luminosityDifference =
197 NS_LUMINOSITY_DIFFERENCE(foreColor, mFrameBackgroundColor);
199 if (mSufficientContrast > luminosityDifference &&
200 customColors->mAltForegroundColor) {
201 int32_t altLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
202 *customColors->mForegroundColor, mFrameBackgroundColor);
204 if (luminosityDifference < altLuminosityDifference) {
205 foreColor = *customColors->mAltForegroundColor;
209 *aForeColor = foreColor;
210 *aBackColor = NS_TRANSPARENT;
211 return;
214 // There are neither mForegroundColor nor mBackgroundColor.
215 *aForeColor = GetTextColor();
216 *aBackColor = NS_TRANSPARENT;
219 bool nsTextPaintStyle::GetCustomHighlightTextColor(nsAtom* aHighlightName,
220 nscolor* aForeColor) {
221 NS_ASSERTION(aForeColor, "aForeColor is null");
223 // non-existing highlights will be stored as `aHighlightName->nullptr`,
224 // so subsequent calls only need a hashtable lookup and don't have
225 // to enter the style engine.
226 RefPtr<ComputedStyle> highlightStyle =
227 mCustomHighlightPseudoStyles.LookupOrInsertWith(
228 aHighlightName, [this, &aHighlightName] {
229 return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
231 if (!highlightStyle) {
232 // highlight `aHighlightName` doesn't exist or has no style rules.
233 return false;
236 *aForeColor = highlightStyle->GetVisitedDependentColor(
237 &nsStyleText::mWebkitTextFillColor);
239 return highlightStyle->HasAuthorSpecifiedTextColor();
242 bool nsTextPaintStyle::GetCustomHighlightBackgroundColor(nsAtom* aHighlightName,
243 nscolor* aBackColor) {
244 NS_ASSERTION(aBackColor, "aBackColor is null");
245 // non-existing highlights will be stored as `aHighlightName->nullptr`,
246 // so subsequent calls only need a hashtable lookup and don't have
247 // to enter the style engine.
248 RefPtr<ComputedStyle> highlightStyle =
249 mCustomHighlightPseudoStyles.LookupOrInsertWith(
250 aHighlightName, [this, &aHighlightName] {
251 return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
253 if (!highlightStyle) {
254 // highlight `aHighlightName` doesn't exist or has no style rules.
255 return false;
258 *aBackColor = highlightStyle->GetVisitedDependentColor(
259 &nsStyleBackground::mBackgroundColor);
260 return NS_GET_A(*aBackColor) != 0;
263 void nsTextPaintStyle::GetURLSecondaryColor(nscolor* aForeColor) {
264 NS_ASSERTION(aForeColor, "aForeColor is null");
266 const nscolor textColor = GetTextColor();
267 *aForeColor = NS_RGBA(NS_GET_R(textColor), NS_GET_G(textColor),
268 NS_GET_B(textColor), 127);
271 void nsTextPaintStyle::GetIMESelectionColors(int32_t aIndex,
272 nscolor* aForeColor,
273 nscolor* aBackColor) {
274 NS_ASSERTION(aForeColor, "aForeColor is null");
275 NS_ASSERTION(aBackColor, "aBackColor is null");
276 NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
278 nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
279 *aForeColor = selectionStyle->mTextColor;
280 *aBackColor = selectionStyle->mBGColor;
283 bool nsTextPaintStyle::GetSelectionUnderlineForPaint(
284 int32_t aIndex, nscolor* aLineColor, float* aRelativeSize,
285 StyleTextDecorationStyle* aStyle) {
286 NS_ASSERTION(aLineColor, "aLineColor is null");
287 NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
288 NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
290 nsSelectionStyle* selectionStyle = GetSelectionStyle(aIndex);
291 if (selectionStyle->mUnderlineStyle == StyleTextDecorationStyle::None ||
292 selectionStyle->mUnderlineColor == NS_TRANSPARENT ||
293 selectionStyle->mUnderlineRelativeSize <= 0.0f)
294 return false;
296 *aLineColor = selectionStyle->mUnderlineColor;
297 *aRelativeSize = selectionStyle->mUnderlineRelativeSize;
298 *aStyle = selectionStyle->mUnderlineStyle;
299 return true;
302 void nsTextPaintStyle::InitCommonColors() {
303 if (mInitCommonColors) {
304 return;
307 auto bgColor = nsCSSRendering::FindEffectiveBackgroundColor(mFrame);
308 mFrameBackgroundColor = bgColor.mColor;
310 mSystemFieldForegroundColor =
311 LookAndFeel::Color(LookAndFeel::ColorID::Fieldtext, mFrame);
312 mSystemFieldBackgroundColor =
313 LookAndFeel::Color(LookAndFeel::ColorID::Field, mFrame);
315 if (bgColor.mIsThemed) {
316 // Assume a native widget has sufficient contrast always
317 mSufficientContrast = 0;
318 mInitCommonColors = true;
319 return;
322 nscolor defaultWindowBackgroundColor =
323 LookAndFeel::Color(LookAndFeel::ColorID::Window, mFrame);
324 nscolor selectionTextColor =
325 LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
326 nscolor selectionBGColor =
327 LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
329 mSufficientContrast = std::min(
330 std::min(NS_SUFFICIENT_LUMINOSITY_DIFFERENCE,
331 NS_LUMINOSITY_DIFFERENCE(selectionTextColor, selectionBGColor)),
332 NS_LUMINOSITY_DIFFERENCE(defaultWindowBackgroundColor, selectionBGColor));
334 mInitCommonColors = true;
337 nscolor nsTextPaintStyle::GetSystemFieldForegroundColor() {
338 InitCommonColors();
339 return mSystemFieldForegroundColor;
342 nscolor nsTextPaintStyle::GetSystemFieldBackgroundColor() {
343 InitCommonColors();
344 return mSystemFieldBackgroundColor;
347 bool nsTextPaintStyle::InitSelectionColorsAndShadow() {
348 if (mInitSelectionColorsAndShadow) {
349 return true;
352 int16_t selectionFlags;
353 const int16_t selectionStatus = mFrame->GetSelectionStatus(&selectionFlags);
354 if (!(selectionFlags & nsISelectionDisplay::DISPLAY_TEXT) ||
355 selectionStatus < nsISelectionController::SELECTION_ON) {
356 // Not displaying the normal selection.
357 // We're not caching this fact, so every call to GetSelectionColors
358 // will come through here. We could avoid this, but it's not really worth
359 // it.
360 return false;
363 mInitSelectionColorsAndShadow = true;
365 // Use ::selection pseudo class if applicable.
366 if (RefPtr<ComputedStyle> style =
367 mFrame->ComputeSelectionStyle(selectionStatus)) {
368 mSelectionBGColor =
369 style->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
370 mSelectionTextColor =
371 style->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
372 mSelectionPseudoStyle = std::move(style);
373 return true;
376 mSelectionTextColor =
377 LookAndFeel::Color(LookAndFeel::ColorID::Highlighttext, mFrame);
379 nscolor selectionBGColor =
380 LookAndFeel::Color(LookAndFeel::ColorID::Highlight, mFrame);
382 switch (selectionStatus) {
383 case nsISelectionController::SELECTION_ATTENTION: {
384 mSelectionTextColor = LookAndFeel::Color(
385 LookAndFeel::ColorID::TextSelectAttentionForeground, mFrame);
386 mSelectionBGColor = LookAndFeel::Color(
387 LookAndFeel::ColorID::TextSelectAttentionBackground, mFrame);
388 mSelectionBGColor =
389 EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
390 break;
392 case nsISelectionController::SELECTION_ON: {
393 mSelectionBGColor = selectionBGColor;
394 break;
396 default: {
397 mSelectionBGColor = LookAndFeel::Color(
398 LookAndFeel::ColorID::TextSelectDisabledBackground, mFrame);
399 mSelectionBGColor =
400 EnsureDifferentColors(mSelectionBGColor, selectionBGColor);
401 break;
405 if (mResolveColors) {
406 EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
408 return true;
411 nsTextPaintStyle::nsSelectionStyle* nsTextPaintStyle::GetSelectionStyle(
412 int32_t aIndex) {
413 InitSelectionStyle(aIndex);
414 return &mSelectionStyle[aIndex];
417 struct StyleIDs {
418 LookAndFeel::ColorID mForeground, mBackground, mLine;
419 LookAndFeel::IntID mLineStyle;
420 LookAndFeel::FloatID mLineRelativeSize;
422 static StyleIDs SelectionStyleIDs[] = {
423 {LookAndFeel::ColorID::IMERawInputForeground,
424 LookAndFeel::ColorID::IMERawInputBackground,
425 LookAndFeel::ColorID::IMERawInputUnderline,
426 LookAndFeel::IntID::IMERawInputUnderlineStyle,
427 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
428 {LookAndFeel::ColorID::IMESelectedRawTextForeground,
429 LookAndFeel::ColorID::IMESelectedRawTextBackground,
430 LookAndFeel::ColorID::IMESelectedRawTextUnderline,
431 LookAndFeel::IntID::IMESelectedRawTextUnderlineStyle,
432 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
433 {LookAndFeel::ColorID::IMEConvertedTextForeground,
434 LookAndFeel::ColorID::IMEConvertedTextBackground,
435 LookAndFeel::ColorID::IMEConvertedTextUnderline,
436 LookAndFeel::IntID::IMEConvertedTextUnderlineStyle,
437 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
438 {LookAndFeel::ColorID::IMESelectedConvertedTextForeground,
439 LookAndFeel::ColorID::IMESelectedConvertedTextBackground,
440 LookAndFeel::ColorID::IMESelectedConvertedTextUnderline,
441 LookAndFeel::IntID::IMESelectedConvertedTextUnderline,
442 LookAndFeel::FloatID::IMEUnderlineRelativeSize},
443 {LookAndFeel::ColorID::End, LookAndFeel::ColorID::End,
444 LookAndFeel::ColorID::SpellCheckerUnderline,
445 LookAndFeel::IntID::SpellCheckerUnderlineStyle,
446 LookAndFeel::FloatID::SpellCheckerUnderlineRelativeSize}};
448 void nsTextPaintStyle::InitSelectionStyle(int32_t aIndex) {
449 NS_ASSERTION(aIndex >= 0 && aIndex < 5, "aIndex is invalid");
450 nsSelectionStyle* selectionStyle = &mSelectionStyle[aIndex];
451 if (selectionStyle->mInit) {
452 return;
455 StyleIDs* styleIDs = &SelectionStyleIDs[aIndex];
457 nscolor foreColor, backColor;
458 if (styleIDs->mForeground == LookAndFeel::ColorID::End) {
459 foreColor = NS_SAME_AS_FOREGROUND_COLOR;
460 } else {
461 foreColor = LookAndFeel::Color(styleIDs->mForeground, mFrame);
463 if (styleIDs->mBackground == LookAndFeel::ColorID::End) {
464 backColor = NS_TRANSPARENT;
465 } else {
466 backColor = LookAndFeel::Color(styleIDs->mBackground, mFrame);
469 // Convert special color to actual color
470 NS_ASSERTION(foreColor != NS_TRANSPARENT,
471 "foreColor cannot be NS_TRANSPARENT");
472 NS_ASSERTION(backColor != NS_SAME_AS_FOREGROUND_COLOR,
473 "backColor cannot be NS_SAME_AS_FOREGROUND_COLOR");
474 NS_ASSERTION(backColor != NS_40PERCENT_FOREGROUND_COLOR,
475 "backColor cannot be NS_40PERCENT_FOREGROUND_COLOR");
477 if (mResolveColors) {
478 foreColor = GetResolvedForeColor(foreColor, GetTextColor(), backColor);
480 if (NS_GET_A(backColor) > 0) {
481 EnsureSufficientContrast(&foreColor, &backColor);
485 nscolor lineColor;
486 float relativeSize;
487 StyleTextDecorationStyle lineStyle;
488 GetSelectionUnderline(mFrame, aIndex, &lineColor, &relativeSize, &lineStyle);
490 if (mResolveColors) {
491 lineColor = GetResolvedForeColor(lineColor, foreColor, backColor);
494 selectionStyle->mTextColor = foreColor;
495 selectionStyle->mBGColor = backColor;
496 selectionStyle->mUnderlineColor = lineColor;
497 selectionStyle->mUnderlineStyle = lineStyle;
498 selectionStyle->mUnderlineRelativeSize = relativeSize;
499 selectionStyle->mInit = true;
502 /* static */
503 bool nsTextPaintStyle::GetSelectionUnderline(nsIFrame* aFrame, int32_t aIndex,
504 nscolor* aLineColor,
505 float* aRelativeSize,
506 StyleTextDecorationStyle* aStyle) {
507 NS_ASSERTION(aFrame, "aFrame is null");
508 NS_ASSERTION(aRelativeSize, "aRelativeSize is null");
509 NS_ASSERTION(aStyle, "aStyle is null");
510 NS_ASSERTION(aIndex >= 0 && aIndex < 5, "Index out of range");
512 StyleIDs& styleID = SelectionStyleIDs[aIndex];
514 nscolor color = LookAndFeel::Color(styleID.mLine, aFrame);
515 const int32_t lineStyle = LookAndFeel::GetInt(styleID.mLineStyle);
516 auto style = static_cast<StyleTextDecorationStyle>(lineStyle);
517 if (lineStyle > static_cast<int32_t>(StyleTextDecorationStyle::Sentinel)) {
518 NS_ERROR("Invalid underline style value is specified");
519 style = StyleTextDecorationStyle::Solid;
521 float size = LookAndFeel::GetFloat(styleID.mLineRelativeSize);
523 NS_ASSERTION(size, "selection underline relative size must be larger than 0");
525 if (aLineColor) {
526 *aLineColor = color;
528 *aRelativeSize = size;
529 *aStyle = style;
531 return style != StyleTextDecorationStyle::None && color != NS_TRANSPARENT &&
532 size > 0.0f;
535 bool nsTextPaintStyle::GetSelectionShadow(
536 Span<const StyleSimpleShadow>* aShadows) {
537 if (!InitSelectionColorsAndShadow()) {
538 return false;
541 if (mSelectionPseudoStyle) {
542 *aShadows = mSelectionPseudoStyle->StyleText()->mTextShadow.AsSpan();
543 return true;
546 return false;
549 inline nscolor Get40PercentColor(nscolor aForeColor, nscolor aBackColor) {
550 nscolor foreColor = NS_RGBA(NS_GET_R(aForeColor), NS_GET_G(aForeColor),
551 NS_GET_B(aForeColor), (uint8_t)(255 * 0.4f));
552 // Don't use true alpha color for readability.
553 return NS_ComposeColors(aBackColor, foreColor);
556 nscolor nsTextPaintStyle::GetResolvedForeColor(nscolor aColor,
557 nscolor aDefaultForeColor,
558 nscolor aBackColor) {
559 if (aColor == NS_SAME_AS_FOREGROUND_COLOR) {
560 return aDefaultForeColor;
563 if (aColor != NS_40PERCENT_FOREGROUND_COLOR) {
564 return aColor;
567 // Get actual background color
568 nscolor actualBGColor = aBackColor;
569 if (actualBGColor == NS_TRANSPARENT) {
570 InitCommonColors();
571 actualBGColor = mFrameBackgroundColor;
573 return Get40PercentColor(aDefaultForeColor, actualBGColor);
576 nscolor nsTextPaintStyle::GetWebkitTextStrokeColor() {
577 if (mFrame->IsInSVGTextSubtree()) {
578 return 0;
580 return mFrame->StyleText()->mWebkitTextStrokeColor.CalcColor(mFrame);
583 float nsTextPaintStyle::GetWebkitTextStrokeWidth() {
584 if (mFrame->IsInSVGTextSubtree()) {
585 return 0.0f;
587 nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth;
588 return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);