Bug 959: add support for accesskeys to XUL. r=hewitt, r=attinasi for changes to layout/html, sr=hyatt, a=asa

This commit is contained in:
jaggernaut%netscape.com 2002-02-21 13:39:39 +00:00
Родитель 039def32af
Коммит 183bc5b700
12 изменённых файлов: 746 добавлений и 174 удалений

Просмотреть файл

@ -86,6 +86,7 @@
#include "nsIFocusController.h"
#include "nsXULAtoms.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMXULDocument.h"
#include "nsIObserverService.h"
#include "nsIDocShell.h"
@ -308,10 +309,10 @@ NS_IMPL_ISUPPORTS3(nsEventStateManager, nsIEventStateManager, nsIObserver, nsISu
NS_IMETHODIMP
nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
nsEvent *aEvent,
nsIFrame* aTargetFrame,
nsEventStatus* aStatus,
nsIView* aView)
nsEvent *aEvent,
nsIFrame* aTargetFrame,
nsEventStatus* aStatus,
nsIView* aView)
{
NS_ENSURE_ARG_POINTER(aStatus);
NS_ENSURE_ARG(aPresContext);
@ -514,11 +515,11 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
if (gLastFocusedContent) {
nsCOMPtr<nsIDocument> doc;
gLastFocusedContent->GetDocument(*getter_AddRefs(doc));
if(doc)
if(doc)
doc->GetScriptGlobalObject(getter_AddRefs(ourGlobal));
else {
mDocument->GetScriptGlobalObject(getter_AddRefs(ourGlobal));
NS_RELEASE(gLastFocusedContent);
mDocument->GetScriptGlobalObject(getter_AddRefs(ourGlobal));
NS_RELEASE(gLastFocusedContent);
}
}
else mDocument->GetScriptGlobalObject(getter_AddRefs(ourGlobal));
@ -606,7 +607,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
focusController->SetActive(PR_TRUE);
}
if (!focusedWindow) {
if (!focusedWindow) {
nsCOMPtr<nsIScriptGlobalObject> globalObject;
mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject));
focusedWindow = do_QueryInterface(globalObject);
@ -756,37 +757,131 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext,
//Alt key is down, we may need to do an accesskey
if (mAccessKeys) {
//Someone registered an accesskey. Find and activate it.
nsAutoString accKey((char)keyEvent->charCode);
ToLowerCase(accKey);
PRUnichar accKey = nsCRT::ToLower((char)keyEvent->charCode);
nsVoidKey key((void*)accKey.First());
nsVoidKey key((void*)accKey);
if (mAccessKeys->Exists(&key)) {
nsCOMPtr<nsIContent> content = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mAccessKeys->Get(&key)));
nsCOMPtr<nsIContent> content = dont_AddRef(NS_STATIC_CAST(nsIContent*, mAccessKeys->Get(&key)));
//Its hard to say what HTML4 wants us to do in all cases. So for now we'll settle for
//A) Set focus
ChangeFocus(content);
PRBool isXUL = content->IsContentOfType(nsIContent::eXUL);
nsresult rv = getPrefService();
PRBool activate = PR_TRUE;
// if it's a XUL element...
if (isXUL) {
if (NS_SUCCEEDED(rv)) {
mPrefService->GetBoolPref("accessibility.accesskeycausesactivation", &activate);
}
// find out what type of content node this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = content->GetTag(*getter_AddRefs(atom));
if (NS_SUCCEEDED(rv) && atom) {
if (atom == nsXULAtoms::label) {
// If anything fails, this will be null ...
nsCOMPtr<nsIDOMElement> element;
nsAutoString control;
content->GetAttr(kNameSpaceID_None, nsXULAtoms::control, control);
if (!control.IsEmpty()) {
nsCOMPtr<nsIDocument> document;
content->GetDocument(*getter_AddRefs(document));
nsCOMPtr<nsIDOMDocument> domDocument = do_QueryInterface(document);
if (domDocument)
domDocument->GetElementById(control, getter_AddRefs(element));
}
// ... that here we'll either change |content| to the element
// referenced by |element|, or clear it.
content = do_QueryInterface(element);
}
}
if (!content)
break;
nsCOMPtr<nsIPresShell> presShell;
aPresContext->GetShell(getter_AddRefs(presShell));
nsIFrame* frame = nsnull;
presShell->GetPrimaryFrameFor(content, &frame);
if (frame) {
const nsStyleVisibility* vis;
frame->GetStyleData(eStyleStruct_Visibility,
((const nsStyleStruct *&)vis));
PRBool viewShown = PR_TRUE;
nsIView* frameView = nsnull;
frame->GetView(mPresContext, &frameView);
if (!frameView) {
nsIFrame* parentWithView = nsnull;
frame->GetParentWithView(mPresContext, &parentWithView);
if (parentWithView)
parentWithView->GetView(mPresContext, &frameView);
}
while (frameView) {
nsViewVisibility visib;
frameView->GetVisibility(visib);
if (visib == nsViewVisibility_kHide) {
viewShown = PR_FALSE;
break;
}
frameView->GetParent(frameView);
}
// get the XUL element
nsCOMPtr<nsIDOMXULElement> element = do_QueryInterface(content);
// if collapsed or hidden, we don't get tabbed into.
if (viewShown &&
vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN &&
element) {
// find out what type of content node this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = content->GetTag(*getter_AddRefs(atom));
if (NS_SUCCEEDED(rv) && atom) {
// define behavior for each type of XUL element:
if (atom == nsXULAtoms::textbox) {
// if it's a text box, give it focus
element->Focus();
} else {
// otherwise, focus and click in it
element->Focus();
element->Click();
}
}
}
}
} else { // otherwise, it must be HTML
// It's hard to say what HTML4 wants us to do in all cases.
// So for now we'll settle for A) Set focus
ChangeFocus(content);
nsresult rv = getPrefService();
PRBool activate = PR_TRUE;
if (NS_SUCCEEDED(rv)) {
mPrefService->GetBoolPref("accessibility.accesskeycausesactivation", &activate);
}
if (activate) {
//B) Click on it if the users prefs indicate to do so.
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
content->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
if (activate) {
//B) Click on it if the users prefs indicate to do so.
nsEventStatus status = nsEventStatus_eIgnore;
nsMouseEvent event;
event.eventStructType = NS_MOUSE_EVENT;
event.message = NS_MOUSE_LEFT_CLICK;
event.isShift = PR_FALSE;
event.isControl = PR_FALSE;
event.isAlt = PR_FALSE;
event.isMeta = PR_FALSE;
event.clickCount = 0;
event.widget = nsnull;
content->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
}
*aStatus = nsEventStatus_eConsumeNoDefault;
@ -1754,8 +1849,8 @@ nsEventStateManager::PostHandleEvent(nsIPresContext* aPresContext,
// force the update to happen now, otherwise multiple scrolls can
// occur before the update is processed. (bug #7354)
nsIViewManager* vm = nsnull;
if (NS_OK == aView->GetViewManager(vm) && nsnull != vm) {
// I'd use Composite here, but it doesn't always work.
if (NS_OK == aView->GetViewManager(vm) && nsnull != vm) {
// I'd use Composite here, but it doesn't always work.
// vm->Composite();
vm->ForceUpdate();
NS_RELEASE(vm);
@ -1774,8 +1869,8 @@ nsEventStateManager::PostHandleEvent(nsIPresContext* aPresContext,
// force the update to happen now, otherwise multiple scrolls can
// occur before the update is processed. (bug #7354)
nsIViewManager* vm = nsnull;
if (NS_OK == aView->GetViewManager(vm) && nsnull != vm) {
// I'd use Composite here, but it doesn't always work.
if (NS_OK == aView->GetViewManager(vm) && nsnull != vm) {
// I'd use Composite here, but it doesn't always work.
// vm->Composite();
vm->ForceUpdate();
NS_RELEASE(vm);
@ -3147,11 +3242,11 @@ nsEventStateManager::GetEventTarget(nsIFrame **aFrame)
}
if (!mCurrentTarget) {
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
presShell->GetEventTargetFrame(&mCurrentTarget);
}
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
presShell->GetEventTargetFrame(&mCurrentTarget);
}
}
*aFrame = mCurrentTarget;
@ -3176,11 +3271,11 @@ nsEventStateManager::GetEventTargetContent(nsEvent* aEvent, nsIContent** aConten
}
if (!mCurrentTarget) {
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
presShell->GetEventTargetFrame(&mCurrentTarget);
}
nsCOMPtr<nsIPresShell> presShell;
mPresContext->GetShell(getter_AddRefs(presShell));
if (presShell) {
presShell->GetEventTargetFrame(&mCurrentTarget);
}
}
if (mCurrentTarget) {
@ -3219,10 +3314,10 @@ nsEventStateManager::GetContentState(nsIContent *aContent, PRInt32& aState)
nsCOMPtr<nsIContent> parent = mHoverContent;
nsIContent* child;
while (parent) {
if (aContent == parent.get()) {
aState |= NS_EVENT_STATE_HOVER;
if (aContent == parent.get()) {
aState |= NS_EVENT_STATE_HOVER;
break;
}
}
child = parent;
child->GetParent(*getter_AddRefs(parent));
}
@ -3291,13 +3386,13 @@ nsEventStateManager::SetContentState(nsIContent *aContent, PRInt32 aState)
while (parent1) {
parent2 = aContent;
while (parent2) {
if (parent1 == parent2) {
if (parent1 == parent2) {
commonHoverParent = parent1;
break;
}
nsIContent* child2 = parent2;
child2->GetParent(*getter_AddRefs(parent2));
}
}
if (commonHoverParent) {
break;
}
@ -3564,7 +3659,7 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
if(newWindow)
newWindow->GetRootFocusController(getter_AddRefs(newFocusController));
if(oldWindow)
oldWindow->GetRootFocusController(getter_AddRefs(oldFocusController));
oldWindow->GetRootFocusController(getter_AddRefs(oldFocusController));
if(oldFocusController && oldFocusController != newFocusController)
oldFocusController->SetSuppressFocus(PR_TRUE, "SendFocusBlur Window Switch");
}
@ -3599,25 +3694,25 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
event.eventStructType = NS_EVENT;
event.message = NS_BLUR_CONTENT;
// Make sure we're not switching command dispatchers, if so, surpress the blurred one
if(mDocument) {
nsCOMPtr<nsIFocusController> newFocusController;
nsCOMPtr<nsIFocusController> oldFocusController;
nsCOMPtr<nsPIDOMWindow> oldPIDOMWindow;
nsCOMPtr<nsPIDOMWindow> newPIDOMWindow;
nsCOMPtr<nsIScriptGlobalObject> oldGlobal;
nsCOMPtr<nsIScriptGlobalObject> newGlobal;
gLastFocusedDocument->GetScriptGlobalObject(getter_AddRefs(oldGlobal));
mDocument->GetScriptGlobalObject(getter_AddRefs(newGlobal));
nsCOMPtr<nsPIDOMWindow> newWindow = do_QueryInterface(newGlobal);
nsCOMPtr<nsPIDOMWindow> oldWindow = do_QueryInterface(oldGlobal);
// Make sure we're not switching command dispatchers, if so, surpress the blurred one
if (mDocument) {
nsCOMPtr<nsIFocusController> newFocusController;
nsCOMPtr<nsIFocusController> oldFocusController;
nsCOMPtr<nsPIDOMWindow> oldPIDOMWindow;
nsCOMPtr<nsPIDOMWindow> newPIDOMWindow;
nsCOMPtr<nsIScriptGlobalObject> oldGlobal;
nsCOMPtr<nsIScriptGlobalObject> newGlobal;
gLastFocusedDocument->GetScriptGlobalObject(getter_AddRefs(oldGlobal));
mDocument->GetScriptGlobalObject(getter_AddRefs(newGlobal));
nsCOMPtr<nsPIDOMWindow> newWindow = do_QueryInterface(newGlobal);
nsCOMPtr<nsPIDOMWindow> oldWindow = do_QueryInterface(oldGlobal);
if (newWindow)
newWindow->GetRootFocusController(getter_AddRefs(newFocusController));
oldWindow->GetRootFocusController(getter_AddRefs(oldFocusController));
if(oldFocusController && oldFocusController != newFocusController)
oldFocusController->SetSuppressFocus(PR_TRUE, "SendFocusBlur Window Switch #2");
}
oldWindow->GetRootFocusController(getter_AddRefs(oldFocusController));
if(oldFocusController && oldFocusController != newFocusController)
oldFocusController->SetSuppressFocus(PR_TRUE, "SendFocusBlur Window Switch #2");
}
nsCOMPtr<nsIEventStateManager> esm;
gLastFocusedPresContext->GetEventStateManager(getter_AddRefs(esm));
@ -3701,11 +3796,11 @@ nsEventStateManager::SendFocusBlur(nsIPresContext* aPresContext, nsIContent *aCo
while (nsnull != ancestor) {
ancestor->GetWidget(window); // addrefs
if (nsnull != window) {
window->SetFocus();
NS_RELEASE(window); // releases. Duh.
break;
}
ancestor->GetParent(ancestor);
window->SetFocus();
NS_RELEASE(window); // releases. Duh.
break;
}
ancestor->GetParent(ancestor);
}
}
}
@ -3783,11 +3878,14 @@ nsEventStateManager::RegisterAccessKey(nsIFrame * aFrame, nsIContent* aContent,
}
if (content) {
nsAutoString accKey((char)aKey);
ToLowerCase(accKey);
PRUnichar accKey = nsCRT::ToLower((char)aKey);
nsVoidKey key((void*)accKey.First());
nsVoidKey key((void*)accKey);
#ifdef DEBUG_jag
nsCOMPtr<nsIContent> oldContent = dont_AddRef(NS_STATIC_CAST(nsIContent*, mAccessKeys->Get(&key)));
NS_ASSERTION(!oldContent, "Overwriting accesskey registration");
#endif
mAccessKeys->Put(&key, content);
}
@ -3809,15 +3907,17 @@ nsEventStateManager::UnregisterAccessKey(nsIFrame * aFrame, nsIContent* aContent
content = aContent;
}
if (content) {
nsAutoString accKey((char)aKey);
ToLowerCase(accKey);
PRUnichar accKey = nsCRT::ToLower((char)aKey);
nsVoidKey key((void*)accKey.First());
nsVoidKey key((void*)accKey);
nsCOMPtr<nsIContent> oldContent = getter_AddRefs(NS_STATIC_CAST(nsIContent*, mAccessKeys->Get(&key)));
if (oldContent != content) {
nsCOMPtr<nsIContent> oldContent = dont_AddRef(NS_STATIC_CAST(nsIContent*, mAccessKeys->Get(&key)));
#ifdef DEBUG_jag
NS_ASSERTION(oldContent == content, "Trying to unregister wrong content");
#endif
if (oldContent != content)
return NS_OK;
}
mAccessKeys->Remove(&key);
}
return NS_OK;

Просмотреть файл

@ -234,6 +234,7 @@ XUL_ATOM(editor, "editor")
//
XUL_ATOM(control, "control")
XUL_ATOM(checkbox, "checkbox")
XUL_ATOM(radio, "radio")
XUL_ATOM(radiogroup, "radiogroup")

Просмотреть файл

@ -2528,6 +2528,45 @@ nsXULElement::NormalizeAttrString(const nsAReadableString& aStr,
return nimgr->GetNodeInfo(aStr, nsnull, kNameSpaceID_None, aNodeInfo);
}
void
nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
{
// If someone changes the accesskey, unregister the old one
//
if (mDocument && !aOldValue.IsEmpty()) {
nsCOMPtr<nsIPresShell> shell;
mDocument->GetShellAt(0, getter_AddRefs(shell));
if (shell) {
PRBool validElement = PR_TRUE;
// find out what type of content node this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = GetTag(*getter_AddRefs(atom));
if (NS_SUCCEEDED(rv) && atom) {
if (atom == nsXULAtoms::label) {
// XXXjag a side-effect is that we filter out anonymous <label>s
// in e.g. <menu>, <menuitem>, <button>. These <label>s inherit
// |accesskey| and would otherwise register themselves, overwriting
// the content we really meant to be registered.
if (!HasAttr(kNameSpaceID_None, nsXULAtoms::control))
validElement = PR_FALSE;
}
}
if (validElement) {
nsCOMPtr<nsIPresContext> presContext;
shell->GetPresContext(getter_AddRefs(presContext));
nsCOMPtr<nsIEventStateManager> esm;
presContext->GetEventStateManager(getter_AddRefs(esm));
nsIContent* content = NS_STATIC_CAST(nsIContent*, this);
esm->UnregisterAccessKey(nsnull, content, aOldValue.First());
}
}
}
}
// XXX attribute code swiped from nsGenericContainerElement
// this class could probably just use nsGenericContainerElement
@ -2640,6 +2679,12 @@ nsXULElement::SetAttr(nsINodeInfo* aNodeInfo,
// Add popup and event listeners
AddListenerFor(aNodeInfo, PR_TRUE);
// If the accesskey attribute changes, unregister it here.
// It will be registered for the new value in the relevant frames.
// Also see nsAreaFrame, nsBoxFrame and nsTextBoxFrame's AttributeChanged
if (aNodeInfo->Equals(nsXULAtoms::accesskey, kNameSpaceID_None))
UnregisterAccessKey(oldValue);
if (mDocument) {
nsCOMPtr<nsIBindingManager> bindingManager;
mDocument->GetBindingManager(getter_AddRefs(bindingManager));
@ -2664,9 +2709,9 @@ nsXULElement::SetAttr(nsINodeInfo* aNodeInfo,
mutation.mAttrName = attrName;
if (!oldValue.IsEmpty())
mutation.mPrevAttrValue = getter_AddRefs(NS_NewAtom(oldValue));
mutation.mPrevAttrValue = dont_AddRef(NS_NewAtom(oldValue));
if (!aValue.IsEmpty())
mutation.mNewAttrValue = getter_AddRefs(NS_NewAtom(aValue));
mutation.mNewAttrValue = dont_AddRef(NS_NewAtom(aValue));
if (modification)
mutation.mAttrChange = nsIDOMMutationEvent::MODIFICATION;
else
@ -2889,6 +2934,12 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID,
nsAutoString oldValue;
attr->GetValue(oldValue);
// If the accesskey attribute is removed, unregister it here
// Also see nsAreaFrame, nsBoxFrame and nsTextBoxFrame's AttributeChanged
if (aNameSpaceID == kNameSpaceID_None &&
(aName == nsXULAtoms::accesskey || aName == nsXULAtoms::control))
UnregisterAccessKey(oldValue);
// Fire mutation listeners
if (HasMutationListeners(NS_STATIC_CAST(nsIStyledContent*, this),
NS_EVENT_BITS_MUTATION_ATTRMODIFIED)) {

Просмотреть файл

@ -618,6 +618,8 @@ protected:
nsIControllers *Controllers() const { return mSlots ? mSlots->mControllers.get() : nsnull; }
nsXULAttributes *Attributes() const { return mSlots ? mSlots->GetAttributes() : nsnull; }
void UnregisterAccessKey(const nsAString& aOldValue);
static nsIXBLService *gXBLService;
};

Просмотреть файл

@ -48,6 +48,12 @@
#include "nsLayoutAtoms.h"
#include "nsISizeOfHandler.h"
#ifdef INCLUDE_XUL
#include "nsINameSpaceManager.h"
#include "nsXULAtoms.h"
#include "nsIEventStateManager.h"
#endif
#undef NOISY_MAX_ELEMENT_SIZE
#undef NOISY_FINAL_SIZE
@ -71,9 +77,118 @@ nsAreaFrame::nsAreaFrame()
{
}
#ifdef INCLUDE_XUL
// If you make changes to this function, check its counterparts
// in nsBoxFrame and nsTextBoxFrame
nsresult
nsAreaFrame::RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg)
{
// if we have no content, we can't do anything
if (!mContent)
return NS_ERROR_FAILURE;
PRBool isXUL = mContent->IsContentOfType(nsIContent::eXUL);
if (!isXUL)
return NS_OK;
// find out what type of element this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = mContent->GetTag(*getter_AddRefs(atom));
if (NS_FAILED(rv))
return rv;
// only support accesskeys for the following elements
if (atom != nsXULAtoms::label)
return NS_OK;
// To filter out <label>s without a control attribute.
// XXXjag a side-effect is that we filter out anonymous <label>s
// in e.g. <menu>, <menuitem>, <button>. These <label>s inherit
// |accesskey| and would otherwise register themselves, overwriting
// the content we really meant to be registered.
if (!mContent->HasAttr(kNameSpaceID_None, nsXULAtoms::control))
return NS_OK;
nsAutoString accessKey;
mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::accesskey, accessKey);
if (accessKey.IsEmpty())
return NS_OK;
// With a valid PresContext we can get the ESM
// and register the access key
nsCOMPtr<nsIEventStateManager> esm;
aPresContext->GetEventStateManager(getter_AddRefs(esm));
rv = NS_OK;
if (esm) {
PRUint32 key = accessKey.First();
if (aDoReg)
rv = esm->RegisterAccessKey(nsnull, mContent, key);
else
rv = esm->UnregisterAccessKey(nsnull, mContent, key);
}
return rv;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// nsIFrame
#ifdef INCLUDE_XUL
NS_IMETHODIMP
nsAreaFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsBlockFrame::Init(aPresContext,
aContent,
aParent,
aContext,
aPrevInFlow);
if (NS_FAILED(rv))
return rv;
// register access key
return RegUnregAccessKey(aPresContext, PR_TRUE);
}
NS_IMETHODIMP
nsAreaFrame::Destroy(nsIPresContext* aPresContext)
{
// unregister access key
RegUnregAccessKey(aPresContext, PR_FALSE);
return nsBlockFrame::Destroy(aPresContext);
}
NS_IMETHODIMP
nsAreaFrame::AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint)
{
nsresult rv = nsBlockFrame::AttributeChanged(aPresContext, aChild,
aNameSpaceID, aAttribute,
aModType, aHint);
// If the accesskey changed, register for the new value
// The old value has been unregistered in nsXULElement::SetAttr
if (aAttribute == nsXULAtoms::accesskey || aAttribute == nsXULAtoms::control)
RegUnregAccessKey(aPresContext, PR_TRUE);
return rv;
}
#endif
NS_IMETHODIMP
nsAreaFrame::GetFrameType(nsIAtom** aType) const
{

Просмотреть файл

@ -58,6 +58,23 @@ public:
// nsIFrame
#ifdef INCLUDE_XUL
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow);
NS_IMETHOD Destroy(nsIPresContext* aPresContext);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint);
#endif
/**
* Get the "type" of the frame
*
@ -73,6 +90,10 @@ public:
protected:
nsAreaFrame();
#ifdef INCLUDE_XUL
nsresult RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg);
#endif
};
#endif /* nsAreaFrame_h___ */

Просмотреть файл

@ -48,6 +48,12 @@
#include "nsLayoutAtoms.h"
#include "nsISizeOfHandler.h"
#ifdef INCLUDE_XUL
#include "nsINameSpaceManager.h"
#include "nsXULAtoms.h"
#include "nsIEventStateManager.h"
#endif
#undef NOISY_MAX_ELEMENT_SIZE
#undef NOISY_FINAL_SIZE
@ -71,9 +77,118 @@ nsAreaFrame::nsAreaFrame()
{
}
#ifdef INCLUDE_XUL
// If you make changes to this function, check its counterparts
// in nsBoxFrame and nsTextBoxFrame
nsresult
nsAreaFrame::RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg)
{
// if we have no content, we can't do anything
if (!mContent)
return NS_ERROR_FAILURE;
PRBool isXUL = mContent->IsContentOfType(nsIContent::eXUL);
if (!isXUL)
return NS_OK;
// find out what type of element this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = mContent->GetTag(*getter_AddRefs(atom));
if (NS_FAILED(rv))
return rv;
// only support accesskeys for the following elements
if (atom != nsXULAtoms::label)
return NS_OK;
// To filter out <label>s without a control attribute.
// XXXjag a side-effect is that we filter out anonymous <label>s
// in e.g. <menu>, <menuitem>, <button>. These <label>s inherit
// |accesskey| and would otherwise register themselves, overwriting
// the content we really meant to be registered.
if (!mContent->HasAttr(kNameSpaceID_None, nsXULAtoms::control))
return NS_OK;
nsAutoString accessKey;
mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::accesskey, accessKey);
if (accessKey.IsEmpty())
return NS_OK;
// With a valid PresContext we can get the ESM
// and register the access key
nsCOMPtr<nsIEventStateManager> esm;
aPresContext->GetEventStateManager(getter_AddRefs(esm));
rv = NS_OK;
if (esm) {
PRUint32 key = accessKey.First();
if (aDoReg)
rv = esm->RegisterAccessKey(nsnull, mContent, key);
else
rv = esm->UnregisterAccessKey(nsnull, mContent, key);
}
return rv;
}
#endif
/////////////////////////////////////////////////////////////////////////////
// nsIFrame
#ifdef INCLUDE_XUL
NS_IMETHODIMP
nsAreaFrame::Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsBlockFrame::Init(aPresContext,
aContent,
aParent,
aContext,
aPrevInFlow);
if (NS_FAILED(rv))
return rv;
// register access key
return RegUnregAccessKey(aPresContext, PR_TRUE);
}
NS_IMETHODIMP
nsAreaFrame::Destroy(nsIPresContext* aPresContext)
{
// unregister access key
RegUnregAccessKey(aPresContext, PR_FALSE);
return nsBlockFrame::Destroy(aPresContext);
}
NS_IMETHODIMP
nsAreaFrame::AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint)
{
nsresult rv = nsBlockFrame::AttributeChanged(aPresContext, aChild,
aNameSpaceID, aAttribute,
aModType, aHint);
// If the accesskey changed, register for the new value
// The old value has been unregistered in nsXULElement::SetAttr
if (aAttribute == nsXULAtoms::accesskey || aAttribute == nsXULAtoms::control)
RegUnregAccessKey(aPresContext, PR_TRUE);
return rv;
}
#endif
NS_IMETHODIMP
nsAreaFrame::GetFrameType(nsIAtom** aType) const
{

Просмотреть файл

@ -58,6 +58,23 @@ public:
// nsIFrame
#ifdef INCLUDE_XUL
NS_IMETHOD Init(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame* aParent,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow);
NS_IMETHOD Destroy(nsIPresContext* aPresContext);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint);
#endif
/**
* Get the "type" of the frame
*
@ -73,6 +90,10 @@ public:
protected:
nsAreaFrame();
#ifdef INCLUDE_XUL
nsresult RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg);
#endif
};
#endif /* nsAreaFrame_h___ */

Просмотреть файл

@ -95,6 +95,9 @@
#include "nsIScrollableView.h"
#include "nsHTMLContainerFrame.h"
#include "nsIWidget.h"
#include "nsIEventStateManager.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsITheme.h"
// Needed for Print Preview
@ -391,6 +394,9 @@ nsBoxFrame::Init(nsIPresContext* aPresContext,
mInner->UpdateMouseThrough();
// register access key
rv = RegUnregAccessKey(aPresContext, PR_TRUE);
return rv;
}
@ -1219,6 +1225,9 @@ nsBoxFrame::Destroy(nsIPresContext* aPresContext)
if (mState & NS_STATE_IS_ROOT)
mInner->GetDebugPref(aPresContext);
// unregister access key
RegUnregAccessKey(aPresContext, PR_FALSE);
SetLayoutManager(nsnull);
// recycle the Inner via the shell's arena.
@ -1359,109 +1368,117 @@ nsBoxFrame::AppendFrames(nsIPresContext* aPresContext,
NS_IMETHODIMP
nsBoxFrame::AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint)
nsIContent* aChild,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType,
PRInt32 aHint)
{
nsresult rv = nsContainerFrame::AttributeChanged(aPresContext, aChild,
aNameSpaceID, aAttribute, aModType, aHint);
nsresult rv = nsContainerFrame::AttributeChanged(aPresContext, aChild,
aNameSpaceID, aAttribute,
aModType, aHint);
if (aAttribute == nsXULAtoms::mousethrough) {
mInner->UpdateMouseThrough();
}
if (aAttribute == nsHTMLAtoms::width ||
aAttribute == nsHTMLAtoms::height ||
aAttribute == nsHTMLAtoms::align ||
aAttribute == nsHTMLAtoms::valign ||
aAttribute == nsHTMLAtoms::left ||
aAttribute == nsHTMLAtoms::top ||
aAttribute == nsXULAtoms::flex ||
aAttribute == nsXULAtoms::orient ||
aAttribute == nsXULAtoms::pack ||
aAttribute == nsXULAtoms::dir ||
aAttribute == nsXULAtoms::mousethrough ||
aAttribute == nsXULAtoms::equalsize) {
if (aAttribute == nsXULAtoms::ordinal) {
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsBoxLayoutState state(shell);
nsIBox* parent;
GetParentBox(&parent);
parent->RelayoutChildAtOrdinal(state, this);
nsIFrame* parentFrame;
parent->GetFrame(&parentFrame);
nsBoxFrame* parentBoxFrame = (nsBoxFrame*) parentFrame;
if (parentBoxFrame)
parentBoxFrame->CheckFrameOrder();
parent->MarkDirty(state);
} else if (aAttribute == nsHTMLAtoms::width ||
aAttribute == nsHTMLAtoms::height ||
aAttribute == nsHTMLAtoms::align ||
if (aAttribute == nsHTMLAtoms::align ||
aAttribute == nsHTMLAtoms::valign ||
aAttribute == nsHTMLAtoms::left ||
aAttribute == nsHTMLAtoms::top ||
aAttribute == nsXULAtoms::flex ||
aAttribute == nsXULAtoms::orient ||
aAttribute == nsXULAtoms::pack ||
aAttribute == nsXULAtoms::dir ||
aAttribute == nsXULAtoms::equalsize) {
aAttribute == nsXULAtoms::orient ||
aAttribute == nsXULAtoms::pack ||
aAttribute == nsXULAtoms::dir ||
aAttribute == nsXULAtoms::debug) {
if (aAttribute == nsXULAtoms::orient || aAttribute == nsXULAtoms::dir ||
aAttribute == nsXULAtoms::debug || aAttribute == nsHTMLAtoms::align ||
aAttribute == nsHTMLAtoms::valign || aAttribute == nsXULAtoms::pack) {
mInner->mValign = nsBoxFrame::vAlign_Top;
mInner->mHalign = nsBoxFrame::hAlign_Left;
mInner->mValign = nsBoxFrame::vAlign_Top;
mInner->mHalign = nsBoxFrame::hAlign_Left;
PRBool orient = PR_TRUE;
GetInitialOrientation(orient);
if (orient)
mState |= NS_STATE_IS_HORIZONTAL;
else
mState &= ~NS_STATE_IS_HORIZONTAL;
PRBool orient = PR_TRUE;
GetInitialOrientation(orient);
if (orient)
mState |= NS_STATE_IS_HORIZONTAL;
else
mState &= ~NS_STATE_IS_HORIZONTAL;
PRBool normal = PR_TRUE;
GetInitialDirection(normal);
if (normal)
mState |= NS_STATE_IS_DIRECTION_NORMAL;
else
mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
PRBool normal = PR_TRUE;
GetInitialDirection(normal);
if (normal)
mState |= NS_STATE_IS_DIRECTION_NORMAL;
else
mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
GetInitialVAlignment(mInner->mValign);
GetInitialHAlignment(mInner->mHalign);
PRBool equalSize = PR_FALSE;
GetInitialEqualSize(equalSize);
if (equalSize)
mState |= NS_STATE_EQUAL_SIZE;
else
mState &= ~NS_STATE_EQUAL_SIZE;
PRBool debug = mState & NS_STATE_SET_TO_DEBUG;
PRBool debugSet = mInner->GetInitialDebug(debug);
if (debugSet) {
mState |= NS_STATE_DEBUG_WAS_SET;
if (debug)
mState |= NS_STATE_SET_TO_DEBUG;
else
mState &= ~NS_STATE_SET_TO_DEBUG;
} else {
mState &= ~NS_STATE_DEBUG_WAS_SET;
}
GetInitialVAlignment(mInner->mValign);
GetInitialHAlignment(mInner->mHalign);
PRBool equalSize = PR_FALSE;
GetInitialEqualSize(equalSize);
if (equalSize)
mState |= NS_STATE_EQUAL_SIZE;
else
mState &= ~NS_STATE_EQUAL_SIZE;
PRBool autostretch = mState & NS_STATE_AUTO_STRETCH;
GetInitialAutoStretch(autostretch);
if (autostretch)
mState |= NS_STATE_AUTO_STRETCH;
else
mState &= ~NS_STATE_AUTO_STRETCH;
}
PRBool debug = mState & NS_STATE_SET_TO_DEBUG;
PRBool debugSet = mInner->GetInitialDebug(debug);
if (debugSet) {
mState |= NS_STATE_DEBUG_WAS_SET;
if (aAttribute == nsHTMLAtoms::left || aAttribute == nsHTMLAtoms::top)
mState &= ~NS_STATE_STACK_NOT_POSITIONED;
if (debug)
mState |= NS_STATE_SET_TO_DEBUG;
else
mState &= ~NS_STATE_SET_TO_DEBUG;
} else {
mState &= ~NS_STATE_DEBUG_WAS_SET;
}
PRBool autostretch = mState & NS_STATE_AUTO_STRETCH;
GetInitialAutoStretch(autostretch);
if (autostretch)
mState |= NS_STATE_AUTO_STRETCH;
else
mState &= ~NS_STATE_AUTO_STRETCH;
}
else if (aAttribute == nsHTMLAtoms::left ||
aAttribute == nsHTMLAtoms::top) {
mState &= ~NS_STATE_STACK_NOT_POSITIONED;
}
else if (aAttribute == nsXULAtoms::mousethrough) {
mInner->UpdateMouseThrough();
}
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsBoxLayoutState state(aPresContext);
MarkDirty(state);
}
else if (aAttribute == nsXULAtoms::ordinal) {
nsCOMPtr<nsIPresShell> shell;
aPresContext->GetShell(getter_AddRefs(shell));
nsBoxLayoutState state(shell);
nsIBox* parent;
GetParentBox(&parent);
parent->RelayoutChildAtOrdinal(state, this);
nsIFrame* parentFrame;
parent->GetFrame(&parentFrame);
nsBoxFrame* parentBoxFrame = (nsBoxFrame*) parentFrame;
if (parentBoxFrame)
parentBoxFrame->CheckFrameOrder();
parent->MarkDirty(state);
}
// If the accesskey changed, register for the new value
// The old value has been unregistered in nsXULElement::SetAttr
else if (aAttribute == nsXULAtoms::accesskey) {
RegUnregAccessKey(aPresContext, PR_TRUE);
}
return rv;
}
@ -2801,4 +2818,52 @@ nsBoxFrame::CreateViewForFrame(nsIPresContext* aPresContext,
return NS_OK;
}
// If you make changes to this function, check its counterparts
// in nsTextBoxFrame and nsAreaFrame
nsresult
nsBoxFrame::RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg)
{
// if we have no content, we can't do anything
if (!mContent)
return NS_ERROR_FAILURE;
// find out what type of element this is
nsCOMPtr<nsIAtom> atom;
nsresult rv = mContent->GetTag(*getter_AddRefs(atom));
if (NS_FAILED(rv))
return rv;
// only support accesskeys for the following elements
if (atom != nsXULAtoms::button &&
atom != nsXULAtoms::checkbox &&
atom != nsXULAtoms::radio) {
return NS_OK;
}
nsAutoString accessKey;
mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::accesskey, accessKey);
if (accessKey.IsEmpty())
return NS_OK;
// With a valid PresContext we can get the ESM
// and register the access key
nsCOMPtr<nsIEventStateManager> esm;
aPresContext->GetEventStateManager(getter_AddRefs(esm));
rv = NS_OK;
if (esm) {
PRUint32 key = accessKey.First();
if (aDoReg)
rv = esm->RegisterAccessKey(nsnull, mContent, key);
else
rv = esm->UnregisterAccessKey(nsnull, mContent, key);
}
return rv;
}

Просмотреть файл

@ -250,8 +250,11 @@ protected:
nscoord mFlex;
nscoord mAscent;
private:
protected:
nsresult RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg);
private:
friend class nsBoxFrameInner;
friend class nsBoxDebug;
nsBoxFrameInner* mInner;

Просмотреть файл

@ -60,6 +60,10 @@
#include "nsIPref.h"
#include "nsXPIDLString.h"
#include "nsIServiceManager.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIEventStateManager.h"
#include "nsITheme.h"
#include "nsUnicharUtils.h"
@ -135,6 +139,11 @@ nsTextBoxFrame::AttributeChanged(nsIPresContext* aPresContext,
Redraw(state);
}
// If the accesskey changed, register for the new value
// The old value has been unregistered in nsXULElement::SetAttr
if (aAttribute == nsXULAtoms::accesskey || aAttribute == nsXULAtoms::control)
RegUnregAccessKey(aPresContext, PR_TRUE);
return NS_OK;
}
@ -158,14 +167,28 @@ nsTextBoxFrame::Init(nsIPresContext* aPresContext,
nsIStyleContext* aContext,
nsIFrame* aPrevInFlow)
{
nsresult rv = nsLeafBoxFrame::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
nsresult rv = nsTextBoxFrameSuper::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow);
if (NS_FAILED(rv))
return rv;
mState |= NS_STATE_NEED_LAYOUT;
PRBool aResize;
PRBool aRedraw;
UpdateAttributes(aPresContext, nsnull, aResize, aRedraw); /* update all */
return rv;
// register access key
RegUnregAccessKey(aPresContext, PR_TRUE);
return NS_OK;
}
NS_IMETHODIMP
nsTextBoxFrame::Destroy(nsIPresContext* aPresContext)
{
// unregister access key
RegUnregAccessKey(aPresContext, PR_FALSE);
return nsTextBoxFrameSuper::Destroy(aPresContext);
}
PRBool
@ -261,6 +284,7 @@ nsTextBoxFrame::UpdateAttributes(nsIPresContext* aPresContext,
UpdateAccessTitle();
aResize = PR_TRUE;
}
}
NS_IMETHODIMP
@ -850,3 +874,49 @@ nsTextBoxFrame::GetFrameName(nsAString& aResult) const
return NS_OK;
}
#endif
// If you make changes to this function, check its counterparts
// in nsBoxFrame and nsAreaFrame
nsresult
nsTextBoxFrame::RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg)
{
// if we have no content, we can't do anything
if (!mContent)
return NS_ERROR_FAILURE;
// check if we have a |control| attribute
// do this check first because few elements have control attributes, and we
// can weed out most of the elements quickly.
// XXXjag a side-effect is that we filter out anonymous <label>s
// in e.g. <menu>, <menuitem>, <button>. These <label>s inherit
// |accesskey| and would otherwise register themselves, overwriting
// the content we really meant to be registered.
if (!mContent->HasAttr(kNameSpaceID_None, nsXULAtoms::control))
return NS_OK;
// see if we even have an access key
nsAutoString accessKey;
mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::accesskey, accessKey);
if (accessKey.IsEmpty())
return NS_OK;
nsresult rv = NS_OK;
// With a valid PresContext we can get the ESM
// and (un)register the access key
nsCOMPtr<nsIEventStateManager> esm;
aPresContext->GetEventStateManager(getter_AddRefs(esm));
if (esm) {
PRUint32 key = accessKey.First();
if (aDoReg)
rv = esm->RegisterAccessKey(nsnull, mContent, key);
else
rv = esm->UnregisterAccessKey(nsnull, mContent, key);
}
return rv;
}

Просмотреть файл

@ -42,7 +42,8 @@
class nsAccessKeyInfo;
class nsTextBoxFrame : public nsLeafBoxFrame
typedef nsLeafBoxFrame nsTextBoxFrameSuper;
class nsTextBoxFrame : public nsTextBoxFrameSuper
{
public:
@ -63,6 +64,8 @@ public:
nsIStyleContext* aContext,
nsIFrame* asPrevInFlow);
NS_IMETHOD Destroy(nsIPresContext* aPresContext);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
PRInt32 aNameSpaceID,
@ -118,6 +121,9 @@ protected:
nsSize& aSize,
nscoord& aAscent);
nsresult RegUnregAccessKey(nsIPresContext* aPresContext,
PRBool aDoReg);
private:
PRBool AlwaysAppendAccessKey();
@ -131,8 +137,10 @@ private:
PRBool mNeedsRecalc;
nsSize mTextSize;
nscoord mAscent;
static PRBool gAlwaysAppendAccessKey;
static PRBool gAccessKeyPrefInitialized;
}; // class nsTextBoxFrame
#endif /* nsTextBoxFrame_h___ */