mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 118308, NS_THEME_TEXTFIELD_CARET implementation (GTK), r+sr=roc
This commit is contained in:
parent
e7c172328a
commit
c6a1fd787c
@ -72,6 +72,7 @@
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsTextFragment.h"
|
||||
#include "nsThemeConstants.h"
|
||||
|
||||
// The bidi indicator hangs off the caret to one side, to show which
|
||||
// direction the typing is in. It needs to be at least 2x2 to avoid looking like
|
||||
@ -123,10 +124,14 @@ NS_IMETHODIMP nsCaret::Init(nsIPresShell *inPresShell)
|
||||
// XXX we should just do this nsILookAndFeel consultation every time
|
||||
// we need these values.
|
||||
mCaretWidthCSSPx = 1;
|
||||
mCaretAspectRatio = 0;
|
||||
if (presContext && (lookAndFeel = presContext->LookAndFeel())) {
|
||||
PRInt32 tempInt;
|
||||
float tempFloat;
|
||||
if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_CaretWidth, tempInt)))
|
||||
mCaretWidthCSSPx = (nscoord)tempInt;
|
||||
if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetricFloat_CaretAspectRatio, tempFloat)))
|
||||
mCaretAspectRatio = tempFloat;
|
||||
if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_CaretBlinkTime, tempInt)))
|
||||
mBlinkRate = (PRUint32)tempInt;
|
||||
if (NS_SUCCEEDED(lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ShowCaretDuringSelection, tempInt)))
|
||||
@ -177,10 +182,12 @@ DrawCJKCaret(nsIFrame* aFrame, PRInt32 aOffset)
|
||||
return 0x2e80 <= ch && ch <= 0xd7ff;
|
||||
}
|
||||
|
||||
nsCaret::Metrics nsCaret::ComputeMetrics(nsIFrame* aFrame, PRInt32 aOffset)
|
||||
nsCaret::Metrics nsCaret::ComputeMetrics(nsIFrame* aFrame, PRInt32 aOffset, nscoord aCaretHeight)
|
||||
{
|
||||
// Compute nominal sizes in appunits
|
||||
nscoord caretWidth = nsPresContext::CSSPixelsToAppUnits(mCaretWidthCSSPx);
|
||||
nscoord caretWidth = (aCaretHeight * mCaretAspectRatio) +
|
||||
nsPresContext::CSSPixelsToAppUnits(mCaretWidthCSSPx);
|
||||
|
||||
if (DrawCJKCaret(aFrame, aOffset)) {
|
||||
caretWidth += nsPresContext::CSSPixelsToAppUnits(1);
|
||||
}
|
||||
@ -367,7 +374,7 @@ NS_IMETHODIMP nsCaret::GetCaretCoordinates(EViewCoordinates aRelativeToType,
|
||||
outCoordinates->x = viewOffset.x;
|
||||
outCoordinates->y = viewOffset.y;
|
||||
outCoordinates->height = theFrame->GetSize().height;
|
||||
outCoordinates->width = ComputeMetrics(theFrame, theFrameOffset).mCaretWidth;
|
||||
outCoordinates->width = ComputeMetrics(theFrame, theFrameOffset, outCoordinates->height).mCaretWidth;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -473,13 +480,36 @@ void nsCaret::UpdateCaretPosition()
|
||||
|
||||
void nsCaret::PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset,
|
||||
nscolor aColor)
|
||||
nsIFrame* aForFrame,
|
||||
const nsPoint &aOffset)
|
||||
{
|
||||
NS_ASSERTION(mDrawn, "The caret shouldn't be drawing");
|
||||
|
||||
aCtx->SetColor(aColor);
|
||||
aCtx->FillRect(mCaretRect + aOffset);
|
||||
const nsRect drawCaretRect = mCaretRect + aOffset;
|
||||
nscolor cssColor = aForFrame->GetStyleColor()->mColor;
|
||||
|
||||
// Only draw the native caret if the foreground color matches that of
|
||||
// -moz-fieldtext (the color of the text in a textbox). If it doesn't match
|
||||
// we are likely in contenteditable or a custom widget and we risk being hard to see
|
||||
// against the background. In that case, fall back to the CSS color.
|
||||
nsPresContext* presContext = aForFrame->PresContext();
|
||||
|
||||
if (GetHookRect().IsEmpty() && presContext) {
|
||||
nsITheme *theme = presContext->GetTheme();
|
||||
if (theme && theme->ThemeSupportsWidget(presContext, aForFrame, NS_THEME_TEXTFIELD_CARET)) {
|
||||
nsILookAndFeel* lookAndFeel = presContext->LookAndFeel();
|
||||
nscolor fieldText;
|
||||
if (NS_SUCCEEDED(lookAndFeel->GetColor(nsILookAndFeel::eColor__moz_fieldtext, fieldText)) &&
|
||||
fieldText == cssColor) {
|
||||
theme->DrawWidgetBackground(aCtx, aForFrame, NS_THEME_TEXTFIELD_CARET,
|
||||
drawCaretRect, drawCaretRect);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aCtx->SetColor(cssColor);
|
||||
aCtx->FillRect(drawCaretRect);
|
||||
if (!GetHookRect().IsEmpty())
|
||||
aCtx->FillRect(GetHookRect() + aOffset);
|
||||
}
|
||||
@ -1176,7 +1206,7 @@ nsresult nsCaret::UpdateCaretRects(nsIFrame* aFrame, PRInt32 aFrameOffset)
|
||||
}
|
||||
|
||||
mCaretRect += framePos;
|
||||
Metrics metrics = ComputeMetrics(aFrame, aFrameOffset);
|
||||
Metrics metrics = ComputeMetrics(aFrame, aFrameOffset, mCaretRect.height);
|
||||
mCaretRect.width = metrics.mCaretWidth;
|
||||
|
||||
// Clamp our position to be within our scroll frame. If we don't, then it
|
||||
|
@ -104,8 +104,8 @@ class nsCaret : public nsICaret,
|
||||
|
||||
void PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset,
|
||||
nscolor aColor);
|
||||
nsIFrame *aForFrame,
|
||||
const nsPoint &aOffset);
|
||||
|
||||
void SetIgnoreUserModify(PRBool aIgnoreUserModify);
|
||||
|
||||
@ -146,7 +146,7 @@ protected:
|
||||
nscoord mBidiIndicatorSize; // width and height of bidi indicator
|
||||
nscoord mCaretWidth; // full caret width including bidi indicator
|
||||
};
|
||||
Metrics ComputeMetrics(nsIFrame* aFrame, PRInt32 aOffset);
|
||||
Metrics ComputeMetrics(nsIFrame* aFrame, PRInt32 aOffset, nscoord aCaretHeight);
|
||||
|
||||
// Returns true if the caret should be drawn. When |mDrawn| is true,
|
||||
// this returns true, so that we erase the drawn caret. If |aIgnoreDrawnState|
|
||||
@ -196,6 +196,7 @@ protected:
|
||||
// probably by ComputeMetrics.
|
||||
PRUint32 mBlinkRate; // time for one cyle (off then on), in milliseconds
|
||||
nscoord mCaretWidthCSSPx; // caret width in CSS pixels
|
||||
float mCaretAspectRatio; // caret width/height aspect ratio
|
||||
|
||||
PRPackedBool mVisible; // is the caret blinking
|
||||
|
||||
|
@ -597,8 +597,7 @@ nsDisplayCaret::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsIRenderingContext* aCtx, const nsRect& aDirtyRect) {
|
||||
// Note: Because we exist, we know that the caret is visible, so we don't
|
||||
// need to check for the caret's visibility.
|
||||
mCaret->PaintCaret(aBuilder, aCtx, aBuilder->ToReferenceFrame(mFrame),
|
||||
mFrame->GetStyleColor()->mColor);
|
||||
mCaret->PaintCaret(aBuilder, aCtx, mFrame, aBuilder->ToReferenceFrame(mFrame));
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -58,8 +58,8 @@ class nsIDOMNode;
|
||||
|
||||
// IID for the nsICaret interface
|
||||
#define NS_ICARET_IID \
|
||||
{ 0x35d82f6b, 0x78f6, 0x4e8a, \
|
||||
{ 0xb9, 0x2a, 0x1a, 0x26, 0xac, 0x2c, 0xe8, 0x53 } }
|
||||
{ 0x48e23b7f, 0x264e, 0xab7d, \
|
||||
{ 0x20, 0x03, 0x2c, 0x79, 0x13, 0xe1, 0x09, 0x4d } }
|
||||
|
||||
|
||||
class nsICaret: public nsISupports
|
||||
@ -182,8 +182,8 @@ public:
|
||||
*/
|
||||
virtual void PaintCaret(nsDisplayListBuilder *aBuilder,
|
||||
nsIRenderingContext *aCtx,
|
||||
const nsPoint &aOffset,
|
||||
nscolor aColor) = 0;
|
||||
nsIFrame *aForFrame,
|
||||
const nsPoint &aOffset) = 0;
|
||||
|
||||
/**
|
||||
* Sets whether the caret should only be visible in nodes that are not
|
||||
|
@ -300,7 +300,11 @@ public:
|
||||
eMetricFloat_ListHorizontalInsidePadding,
|
||||
eMetricFloat_ButtonVerticalInsidePadding,
|
||||
eMetricFloat_ButtonHorizontalInsidePadding,
|
||||
eMetricFloat_IMEUnderlineRelativeSize
|
||||
eMetricFloat_IMEUnderlineRelativeSize,
|
||||
|
||||
// The width/height ratio of the cursor. If used, the CaretWidth int metric
|
||||
// should be added to the calculated caret width.
|
||||
eMetricFloat_CaretAspectRatio
|
||||
} nsMetricFloatID;
|
||||
|
||||
NS_IMETHOD GetColor(const nsColorID aID, nscolor &aColor) = 0;
|
||||
|
@ -1442,6 +1442,17 @@ moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
|
||||
return MOZ_GTK_SUCCESS;
|
||||
}
|
||||
|
||||
static gint
|
||||
moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect,
|
||||
GdkRectangle* cliprect, GtkTextDirection direction)
|
||||
{
|
||||
ensure_entry_widget();
|
||||
gtk_draw_insertion_cursor(gEntryWidget, drawable, cliprect,
|
||||
rect, TRUE, direction, FALSE);
|
||||
|
||||
return MOZ_GTK_SUCCESS;
|
||||
}
|
||||
|
||||
static gint
|
||||
moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
|
||||
GdkRectangle* cliprect, GtkWidgetState* state,
|
||||
@ -2784,6 +2795,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
|
||||
case MOZ_GTK_TOOLBAR:
|
||||
case MOZ_GTK_MENUBAR:
|
||||
case MOZ_GTK_TAB_SCROLLARROW:
|
||||
case MOZ_GTK_ENTRY_CARET:
|
||||
*left = *top = *right = *bottom = 0;
|
||||
return MOZ_GTK_SUCCESS;
|
||||
default:
|
||||
@ -3052,6 +3064,9 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
|
||||
return moz_gtk_entry_paint(drawable, rect, cliprect, state,
|
||||
gEntryWidget, direction);
|
||||
break;
|
||||
case MOZ_GTK_ENTRY_CARET:
|
||||
return moz_gtk_caret_paint(drawable, rect, cliprect, direction);
|
||||
break;
|
||||
case MOZ_GTK_DROPDOWN:
|
||||
return moz_gtk_combo_box_paint(drawable, rect, cliprect, state,
|
||||
(gboolean) flags, direction);
|
||||
|
@ -144,6 +144,8 @@ typedef enum {
|
||||
MOZ_GTK_GRIPPER,
|
||||
/* Paints a GtkEntry. */
|
||||
MOZ_GTK_ENTRY,
|
||||
/* Paints the native caret (or in GTK-speak: insertion cursor) */
|
||||
MOZ_GTK_ENTRY_CARET,
|
||||
/* Paints a GtkOptionMenu. */
|
||||
MOZ_GTK_DROPDOWN,
|
||||
/* Paints a dropdown arrow (a GtkButton containing a down GtkArrow). */
|
||||
|
@ -58,6 +58,7 @@ nscolor nsLookAndFeel::sButtonOuterLightBorder = 0;
|
||||
nscolor nsLookAndFeel::sButtonInnerDarkBorder = 0;
|
||||
nscolor nsLookAndFeel::sOddCellBackground = 0;
|
||||
PRUnichar nsLookAndFeel::sInvisibleCharacter = PRUnichar('*');
|
||||
float nsLookAndFeel::sCaretRatio = 0;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
@ -609,6 +610,9 @@ NS_IMETHODIMP nsLookAndFeel::GetMetric(const nsMetricFloatID aID,
|
||||
case eMetricFloat_IMEUnderlineRelativeSize:
|
||||
aMetric = 1.0f;
|
||||
break;
|
||||
case eMetricFloat_CaretAspectRatio:
|
||||
aMetric = sCaretRatio;
|
||||
break;
|
||||
default:
|
||||
aMetric = -1.0;
|
||||
res = NS_ERROR_FAILURE;
|
||||
@ -733,6 +737,12 @@ nsLookAndFeel::InitLookAndFeel()
|
||||
guint value;
|
||||
g_object_get (entry, "invisible-char", &value, NULL);
|
||||
sInvisibleCharacter = PRUnichar(value);
|
||||
|
||||
// caret styles
|
||||
gtk_widget_style_get(entry,
|
||||
"cursor-aspect-ratio", &sCaretRatio,
|
||||
NULL);
|
||||
|
||||
gtk_widget_destroy(entry);
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,7 @@ protected:
|
||||
static nscolor sButtonInnerDarkBorder;
|
||||
static nscolor sOddCellBackground;
|
||||
static PRUnichar sInvisibleCharacter;
|
||||
static float sCaretRatio;
|
||||
|
||||
static void InitLookAndFeel();
|
||||
void InitWidget() {
|
||||
|
@ -439,6 +439,9 @@ nsNativeThemeGTK::GetGtkWidgetAndState(PRUint8 aWidgetType, nsIFrame* aFrame,
|
||||
case NS_THEME_TEXTFIELD_MULTILINE:
|
||||
aGtkWidgetType = MOZ_GTK_ENTRY;
|
||||
break;
|
||||
case NS_THEME_TEXTFIELD_CARET:
|
||||
aGtkWidgetType = MOZ_GTK_ENTRY_CARET;
|
||||
break;
|
||||
case NS_THEME_LISTBOX:
|
||||
case NS_THEME_TREEVIEW:
|
||||
aGtkWidgetType = MOZ_GTK_TREEVIEW;
|
||||
@ -1326,7 +1329,7 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
|
||||
// case NS_THEME_SCROLLBAR_GRIPPER_VERTICAL: (n/a for gtk)
|
||||
case NS_THEME_TEXTFIELD:
|
||||
case NS_THEME_TEXTFIELD_MULTILINE:
|
||||
// case NS_THEME_TEXTFIELD_CARET:
|
||||
case NS_THEME_TEXTFIELD_CARET:
|
||||
case NS_THEME_DROPDOWN_TEXTFIELD:
|
||||
case NS_THEME_SCALE_HORIZONTAL:
|
||||
case NS_THEME_SCALE_THUMB_HORIZONTAL:
|
||||
|
@ -143,6 +143,8 @@ nsLookAndFeelFloatPref nsXPLookAndFeel::sFloatPrefs[] =
|
||||
PR_FALSE, nsLookAndFeelTypeFloat, 0 },
|
||||
{ "ui.IMEUnderlineRelativeSize", eMetricFloat_IMEUnderlineRelativeSize,
|
||||
PR_FALSE, nsLookAndFeelTypeFloat, 0 },
|
||||
{ "ui.caretAspectRatio", eMetricFloat_CaretAspectRatio, PR_FALSE,
|
||||
nsLookAndFeelTypeFloat, 0 },
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user