public void MouseDown(UIMouseDownEventArgs e, CssBox startAt)
        {
            if (!_isBinded)
            {
                return;
            }
            if (startAt == null)
            {
                return;
            }
            //----------------------------------------------------
            if (!e.Shift)
            {
                ClearPreviousSelection();
            }

            if (_latestMouseDownChain != null)
            {
                ReleaseHitChain(_latestMouseDownChain);
                _latestMouseDownChain = null;
            }
            _lastDomLayoutVersion = _htmlVisualRoot.LayoutVersion;
            //----------------------------------------------------
            int x = e.X;
            int y = e.Y;

            _mouseDownStartAt = startAt;
            _mousedownX       = x;
            _mousedownY       = y;
            CssBoxHitChain hitChain = GetFreeHitChain();

#if DEBUG
            hitChain.debugEventPhase = CssBoxHitChain.dbugEventPhase.MouseDown;
#endif
            hitChain.SetRootGlobalPosition(x, y);
            //1. hittest
            BoxHitUtils.HitTest(startAt, x, y, hitChain);
            //2. propagate events
            SetEventOrigin(e, hitChain);
            ForEachOnlyEventPortalBubbleUp(e, hitChain, portal =>
            {
                portal.PortalMouseDown(e);
                return(true);
            });
            if (!e.CancelBubbling)
            {
                IUIEventListener prevMouseDownElement = _currentMouseDown;
                _currentMouseDown = null; //clear
                e.SetCurrentContextElement(null);
                ForEachEventListenerBubbleUp(e, hitChain, () =>
                {
                    //TODO: check accept keyboard
                    _currentMouseDown = e.CurrentContextElement;
                    e.CurrentContextElement.ListenMouseDown(e);
                    if (prevMouseDownElement != null &&
                        prevMouseDownElement != _currentMouseDown)
                    {
                        prevMouseDownElement.ListenLostMouseFocus(_mouseLostFocus);
                    }

                    return(e.CancelBubbling);
                });
            }
            //----------------------------------
            //save mousedown hitchain
            _latestMouseDownChain = hitChain;
        }
        void IEventPortal.PortalMouseDown(UIMouseDownEventArgs e)
        {
#if DEBUG
            if (this.dbugRootGraphics != null && this.dbugRootGraphics.dbugEnableGraphicInvalidateTrace)
            {
                this.dbugRootGraphics.dbugGraphicInvalidateTracer.WriteInfo("================");
                this.dbugRootGraphics.dbugGraphicInvalidateTracer.WriteInfo("MOUSEDOWN");
                this.dbugRootGraphics.dbugGraphicInvalidateTracer.WriteInfo("================");
            }
            dbugMsgChainVersion = 1;
            int local_msgVersion = 1;
#endif
            HitChain hitPointChain = GetFreeHitChain();
#if DEBUG
            _dbugHitChainPhase = dbugHitChainPhase.MouseDown;
#endif
            HitTestCoreWithPrevChainHint(hitPointChain, _previousChain, e.X, e.Y);

            if (hitPointChain.Count > 0)
            {
                //------------------------------
                //1. origin object
                SetEventOrigin(e, hitPointChain);
                //------------------------------

                _currentMouseDown = null;
                //portal
                ForEachOnlyEventPortalBubbleUp(e, hitPointChain, (e1, portal) =>
                {
                    //please ensure=> no local var/pararmeter capture inside lambda
                    portal.PortalMouseDown(e1);
                    //*****
                    _currentMouseDown = e1.CurrentContextElement;
                    return(true);
                });
                //------------------------------
                //use events
                if (!e.CancelBubbling)
                {
                    _currentMouseDown = null; //clear
                    e.SetCurrentContextElement(null);

                    ForEachEventListenerBubbleUp(e, hitPointChain, (e1, listener) =>
                    {
                        //please ensure=> no local var/pararmeter capture inside lambda
                        if (listener.BypassAllMouseEvents)
                        {
                            return(false);
                        }
                        _currentMouseDown = listener;

                        listener.ListenMouseDown(e1);

                        //-------------------------------------------------------
                        //auto begin monitor mouse press
                        _mousePressMonitor.AddMousePressInformation(e1);
                        _mousePressMonitor.SetMonitoredElement(listener);
                        //-------------------------------------------------------
                        bool cancelMouseBubbling = e1.CancelBubbling;
                        if (_prevMouseDownElement != null &&
                            _prevMouseDownElement != listener)
                        {
                            _prevMouseDownElement.ListenLostMouseFocus(_mouseLostFocusArgs);
                            _prevMouseDownElement = null;//clear
                        }
                        //-------------------------------------------------------
                        //retrun true to stop this loop (no further bubble up)
                        //return false to bubble this to upper control
                        return(e1.CancelBubbling || !listener.BypassAllMouseEvents);
                    });

                    if (_currentMouseDown == null)
                    {
                        _mousePressMonitor.Reset();
                    }
                }

                if (_prevMouseDownElement != _currentMouseDown &&
                    _prevMouseDownElement != null)
                {
                    //TODO: review here, auto or manual
                    _prevMouseDownElement.ListenLostMouseFocus(_mouseLostFocusArgs);
                    _prevMouseDownElement = null;
                }
            }
            //---------------------------------------------------------------

#if DEBUG
            RootGraphic dbug_visualroot = this.dbugRootGraphics;
            if (dbug_visualroot != null && dbug_visualroot.dbug_RecordHitChain)
            {
                dbug_visualroot.dbug_rootHitChainMsg.Clear();
                HitInfo hitInfo;
                for (int tt = hitPointChain.Count - 1; tt >= 0; --tt)
                {
                    hitInfo = hitPointChain.GetHitInfo(tt);
                    RenderElement ve = hitInfo.HitElemAsRenderElement;
                    if (ve != null)
                    {
                        ve.dbug_WriteOwnerLayerInfo(dbug_visualroot, tt);
                        ve.dbug_WriteOwnerLineInfo(dbug_visualroot, tt);
                        string hit_info = new string('.', tt) + " [" + tt + "] "
                                          + "(" + hitInfo.point.X + "," + hitInfo.point.Y + ") "
                                          + ve.dbug_FullElementDescription();
                        dbug_visualroot.dbug_rootHitChainMsg.AddLast(new dbugLayoutMsg(ve, hit_info));
                    }
                }
            }
#endif

            SwapHitChain(hitPointChain);

            e.StopPropagation(); //TODO: review this again
#if DEBUG
            if (local_msgVersion != dbugMsgChainVersion)
            {
                return;
            }
            dbug_visualroot.dbugHitTracker.Write("stop-mousedown");
            dbug_visualroot.dbugHitTracker.Play = false;
#endif
        }