diff --git a/mozilla/layout/html/base/src/nsSelectsAreaFrame.cpp b/mozilla/layout/html/base/src/nsSelectsAreaFrame.cpp index 5ac39a7a0dd..e80156379a1 100644 --- a/mozilla/layout/html/base/src/nsSelectsAreaFrame.cpp +++ b/mozilla/layout/html/base/src/nsSelectsAreaFrame.cpp @@ -40,6 +40,7 @@ #include "nsIDOMHTMLOptionElement.h" #include "nsIContent.h" #include "nsIStyleContext.h" +#include "nsListControlFrame.h" nsresult NS_NewSelectsAreaFrame(nsIPresShell* aShell, nsIFrame** aNewFrame, PRUint32 aFlags) @@ -131,3 +132,18 @@ nsSelectsAreaFrame::GetFrameForPoint(nsIPresContext* aPresContext, return result; } + +NS_IMETHODIMP +nsSelectsAreaFrame::Paint(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + PRUint32 aFlags) +{ + nsresult rv = nsAreaFrame::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, aFlags); + // This assumes that that the ListControlFrame is the Parent + nsListControlFrame* listFrame = NS_STATIC_CAST(nsListControlFrame*, mParent); + listFrame->PaintFocus(aRenderingContext, aWhichLayer); + + return rv; +} \ No newline at end of file diff --git a/mozilla/layout/html/base/src/nsSelectsAreaFrame.h b/mozilla/layout/html/base/src/nsSelectsAreaFrame.h index 52228850f6a..9b1a5e2c005 100644 --- a/mozilla/layout/html/base/src/nsSelectsAreaFrame.h +++ b/mozilla/layout/html/base/src/nsSelectsAreaFrame.h @@ -56,6 +56,11 @@ public: NS_IMETHOD GetFrameForPoint(nsIPresContext* aPresContext, const nsPoint& aPoint, nsFramePaintLayer aWhichLayer, nsIFrame** aFrame); + NS_IMETHOD Paint(nsIPresContext* aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer, + PRUint32 aFlags = 0); protected: PRBool IsOptionElement(nsIContent* aContent); PRBool IsOptionElementFrame(nsIFrame *aFrame); diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp index 58e61aa3549..66bfa1aeba6 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp @@ -51,6 +51,7 @@ #include "nsIDOMHTMLCollection.h" #include "nsIDOMNSHTMLOptionCollectn.h" #include "nsIDOMHTMLSelectElement.h" +#include "nsIDOMNSHTMLSelectElement.h" #include "nsIDOMHTMLOptionElement.h" #include "nsIComboboxControlFrame.h" #include "nsIViewManager.h" @@ -82,6 +83,8 @@ #endif #include "nsISelectElement.h" #include "nsIPrivateDOMEvent.h" +#include "nsCSSRendering.h" +#include "nsILookAndFeel.h" // Timer Includes #include "nsITimer.h" @@ -94,7 +97,9 @@ const PRInt32 kNothingSelected = -1; const PRInt32 kMaxZ = 0x7fffffff; //XXX: Shouldn't there be a define somewhere for MaxInt for PRInt32 const PRInt32 kNoSizeSpecified = -1; -// We now use the :checked pseudoclass for the option selected state + +nsListControlFrame * nsListControlFrame::mFocused = nsnull; + //--------------------------------------------------------- nsresult @@ -522,6 +527,176 @@ nsListControlFrame::Paint(nsIPresContext* aPresContext, } +void nsListControlFrame::PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer aWhichLayer) +{ + if (NS_FRAME_PAINT_LAYER_FOREGROUND != aWhichLayer) return; + + if (mFocused != this) return; + + // The mEndSelectionIndex is what is currently being selected + // use the selected index if this is kNothingSelected + PRInt32 focusedIndex; + if (mEndSelectionIndex == kNothingSelected) { + GetSelectedIndex(&focusedIndex); + } else { + focusedIndex = mEndSelectionIndex; + } + + nsIScrollableView * scrollableView; + GetScrollableView(scrollableView); + if (!scrollableView) return; + + nsCOMPtr presShell; + mPresContext->GetShell(getter_AddRefs(presShell)); + if (!presShell) return; + + nsIFrame* containerFrame; + GetOptionsContainer(mPresContext, &containerFrame); + if (!containerFrame) return; + + nsIFrame * childframe = nsnull; + nsresult result = NS_ERROR_FAILURE; + + nsCOMPtr focusedContent; + + nsCOMPtr selectNSElement(do_QueryInterface(mContent)); + NS_ASSERTION(selectNSElement, "Can't be null"); + + nsCOMPtr selectElement(do_QueryInterface(mContent)); + NS_ASSERTION(selectElement, "Can't be null"); + + // If we have a selected index then get that child frame + if (focusedIndex != kNothingSelected) { + focusedContent = getter_AddRefs(GetOptionContent(focusedIndex)); + // otherwise we find the focusedContent's frame and scroll to it + if (focusedContent) { + result = presShell->GetPrimaryFrameFor(focusedContent, &childframe); + } + } else { + nsCOMPtr selectHTMLElement(do_QueryInterface(mContent)); + NS_ASSERTION(selectElement, "Can't be null"); + + // Since there isn't a selected item we need to show a focus ring around the first + // non-disabled item and skip all the option group elements (nodes) + nsCOMPtr node; + + PRUint32 length; + selectHTMLElement->GetLength(&length); + if (length) { + // find the first non-disabled item + PRBool isDisabled = PR_TRUE; + for (PRInt32 i=0;iItem(i, getter_AddRefs(node))) || !node) { + break; + } + if (NS_FAILED(selectElement->IsOptionDisabled(i, &isDisabled))) { + break; + } + if (isDisabled) { + node = nsnull; + } else { + break; + } + } + if (!node) { + return; + } + } + + // if we found a node use, if not get the first child (this is for empty selects) + if (node) { + focusedContent = do_QueryInterface(node); + result = presShell->GetPrimaryFrameFor(focusedContent, &childframe); + } + if (!childframe) { + // The only way we can get right here is that there are no options + // and we need to get the dummy frame so it has the focus ring + result = containerFrame->FirstChild(mPresContext, nsnull, &childframe); + } + } + + if (NS_FAILED(result) || !childframe) return; + + const nsIView * clippedView; + scrollableView->GetClipView(&clippedView); + if (!clippedView) return; + + nscoord x; + nscoord y; + scrollableView->GetScrollPosition(x,y); + // get the clipped rect + nsRect rect; + clippedView->GetBounds(rect); + + // now move it by the offset of the scroll position + rect.x = 0; + rect.y = 0; + rect.MoveBy(x,y); + + // get the child rect + nsRect fRect; + childframe->GetRect(fRect); + + nsRect clipRect; + containerFrame->GetRect(clipRect); + clipRect.x = 0; + clipRect.y = 0; + + PRBool clipEmpty; + aRC.PushState(); + aRC.SetClipRect(clipRect, nsClipCombine_kReplace, clipEmpty); + + // adjust position is it is a child of a option group + if (focusedContent) { + nsRect optRect(0,0,0,0); + nsCOMPtr parentContent; + focusedContent->GetParent(*getter_AddRefs(parentContent)); + nsCOMPtr optGroup(do_QueryInterface(parentContent)); + if (optGroup) { + nsIFrame * optFrame; + result = presShell->GetPrimaryFrameFor(parentContent, &optFrame); + if (NS_SUCCEEDED(result) && optFrame) { + optFrame->GetRect(optRect); + } + } + fRect.y += optRect.y; + } + + PRBool lastItemIsSelected = PR_FALSE; + nsCOMPtr node; + if (NS_SUCCEEDED(selectNSElement->Item(focusedIndex, getter_AddRefs(node)))) { + nsCOMPtr domOpt(do_QueryInterface(node)); + if (domOpt) { + selectElement->IsOptionSelected(domOpt, &lastItemIsSelected); + } + } + + // set up back stop colors and then ask L&F service for the real colors + nscolor color; + nsCOMPtr lookAndFeel; + mPresContext->GetLookAndFeel(getter_AddRefs(lookAndFeel)); + if (lookAndFeel){ + lookAndFeel->GetColor(lastItemIsSelected?nsILookAndFeel::eColor_WidgetSelectForeground:nsILookAndFeel::eColor_WidgetSelectBackground, color); + } else { + // Use some backstop colors if for some reason we don't have a L&F object + color = lastItemIsSelected? NS_RGB(245,219,149) : NS_RGB(0,0,0); + } + + float p2t; + mPresContext->GetScaledPixelsToTwips(&p2t); + nscoord onePixelInTwips = NSToCoordRound(p2t); + + nsRect dirty; + nscolor colors[] = {color, color, color, color}; + PRUint8 borderStyle[] = {NS_STYLE_BORDER_STYLE_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED, NS_STYLE_BORDER_STYLE_DOTTED}; + nsRect innerRect = fRect; + innerRect.Deflate(nsSize(onePixelInTwips, onePixelInTwips)); + nsCSSRendering::DrawDashedSides(0, aRC, dirty, borderStyle, colors, fRect, innerRect, 0, nsnull); + + aRC.PopState(clipEmpty); + +} + //--------------------------------------------------------- // Frames are not refcounted, no need to AddRef NS_IMETHODIMP @@ -1831,7 +2006,18 @@ nsListControlFrame::GetName(nsAString* aResult) void nsListControlFrame::SetFocus(PRBool aOn, PRBool aRepaint) { - // XXX:TODO Make set focus work + if (aOn) { + PRInt32 selectedIndex; + GetSelectedIndex(&selectedIndex); + ScrollToIndex(selectedIndex); + mFocused = this; + } else { + mFocused = nsnull; + } + + // Make sure the SelectArea frame gets painted + Invalidate(mPresContext, nsRect(0,0,mRect.width,mRect.height), PR_TRUE); + } //--------------------------------------------------------- @@ -3311,6 +3497,10 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent) presShell->FlushPendingNotifications(PR_FALSE); } REFLOW_DEBUG_MSG2(" After: %d\n", newIndex); + + // Make sure the SelectArea frame gets painted + Invalidate(mPresContext, nsRect(0,0,mRect.width,mRect.height), PR_TRUE); + } else { REFLOW_DEBUG_MSG(" After: SKIPPED it\n"); } diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.h b/mozilla/layout/html/forms/src/nsListControlFrame.h index e6c93e4d526..49b3b4cd391 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.h +++ b/mozilla/layout/html/forms/src/nsListControlFrame.h @@ -320,6 +320,8 @@ public: // Helper void SetPassId(PRInt16 aId) { mPassId = aId; } + void PaintFocus(nsIRenderingContext& aRC, nsFramePaintLayer aWhichLayer); + protected: nsresult IsOptionDisabled(PRInt32 anIndex, PRBool &aIsDisabled); @@ -422,6 +424,8 @@ protected: nsSize mCachedUnconstrainedSize; nsSize mCachedAvailableSize; + static nsListControlFrame * mFocused; + #ifdef DO_REFLOW_COUNTER PRInt32 mReflowId; #endif