Bug 118308, NS_THEME_TEXTFIELD_CARET implementation (GTK), r+sr=roc

This commit is contained in:
Michael Ventnor 2008-06-23 11:50:52 +03:00
parent e7c172328a
commit c6a1fd787c
11 changed files with 86 additions and 19 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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). */

View File

@ -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);
}

View File

@ -73,6 +73,7 @@ protected:
static nscolor sButtonInnerDarkBorder;
static nscolor sOddCellBackground;
static PRUnichar sInvisibleCharacter;
static float sCaretRatio;
static void InitLookAndFeel();
void InitWidget() {

View File

@ -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:

View File

@ -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 },
};