//+--------------------------------------------------------------------------- // // Member: CRichtextLayout::DrawClient // // Synopsis: Draw client rect part of the controls // // Arguments: prcBounds bounding rect of display leaf node // prcRedraw rect to be redrawn // pSurface surface to render into // pDispNode pointer to display node // pClientData client-dependent data for drawing pass // dwFlags flags for optimization // //---------------------------------------------------------------------------- void CRichtextLayout::DrawClient( const RECT* prcBounds, const RECT* prcRedraw, CDispSurface* pDispSurface, CDispNode* pDispNode, void* cookie, void* pClientData, DWORD dwFlags) { Assert(pClientData); CFormDrawInfo* pDI = (CFormDrawInfo*)pClientData; { // we set draw surface information separately for Draw() and // the stuff below, because the Draw method of some subclasses // (like CFlowLayout) puts pDI into a special device coordinate // mode CSetDrawSurface sds(pDI, prcBounds, prcRedraw, pDispSurface); Draw(pDI); } { // see comment above CSetDrawSurface sds(pDI, prcBounds, prcRedraw, pDispSurface); // We only want to paint selection on the client rect in this part // In RTL the scrollbar is on the left and will leave extra highlighting // on the right side of the control if we do not adjust it here if(_fTextSelected) { DrawTextSelectionForRect(pDI->GetDC(), (CRect*)prcRedraw , &pDI->_rcClip, _fSwapColor); } if(GetView()->IsFlagSet(CView::VF_ZEROBORDER)) { CLayout* pParentLayout = GetUpdatedParentLayout(); if(pParentLayout && pParentLayout->ElementOwner()->IsEditable()) { DrawZeroBorder(pDI); } } } }
// This function is a callback from LineServices (the pfnFmt callback) // Line services calls this to get the formattnig information for // a non-text object in the layout, i.e. an image or a table or a div. // We create a dobj and give it back to LS here. // This is like a dobj constructor. LSERR WINAPI CEmbeddedILSObj::Fmt(/*[in]*/PCFMTIN pfmtin, /*[out]*/FMTRES* pfmtres) { LSTRACE(Fmt); BOOL fOwnLine; INT xMinWidth; LONG cchSite; LONG xWidth, yHeight; OBJDIM objdim; stylePosition bPositionType; LSERR lserr = lserrNone; CLineServices* pLS = _pLS; CFlowLayout* pFlowLayout = pLS->_pFlowLayout; PLSRUN plsrun = PLSRUN(pfmtin->lsfrun.plsrun); CLayout* pLayout = plsrun->GetLayout(pFlowLayout); CElement* pElementLayout; CTreeNode* pNodeLayout; const CCharFormat* pCF; const CFancyFormat* pFF; CEmbeddedDobj* pdobj = new CEmbeddedDobj(this, pfmtin->plsdnTop); if(!pdobj) { lserr = lserrOutOfMemory; goto Cleanup; } // pLayout is the guy we're being asked to format here. Assert(pLayout && pLayout!=pFlowLayout); pElementLayout = pLayout->ElementOwner(); pNodeLayout = pElementLayout->GetFirstBranch(); pCF = pNodeLayout->GetCharFormat(); pFF = pNodeLayout->GetFancyFormat(); bPositionType = pNodeLayout->GetCascadedposition(); // for overlapping layouts curtail the range of characters measured cchSite = pLS->GetNestedElementCch(pElementLayout); ZeroMemory(&objdim, sizeof(OBJDIM)); // Let's see if this an 'ownline' thingy. Note that even if the element // is not by default and 'ownline' element, we may have morphed it into // one -- then too it has to be a block element. If it is not one (like // a span, then it will not live on its own line). Check here. fOwnLine = pLS->IsOwnLineSite(plsrun); Assert(pElementLayout->IsInlinedElement()); // Certain sites that only Microsoft supports can break with any // characters, so we hack that in right here. // BUGBUG (cthrash) This is goofy. We should have a better way to // determine this than checking tag types. pdobj->_fIsBreakingSite= pElementLayout->Tag()==ETAG_OBJECT || pElementLayout->Tag()==ETAG_MARQUEE // This is really unfortunate -- if a site is percent sized then it becomes a breaking // site inside table cells. This is primarily for IE4x compat. See IE bug 42336 (SujalP) || pFF->_cuvWidth.GetUnitType()==CUnitValue::UNIT_PERCENT // One last thing - if we have a morphed non-ownline element inside // a table, it's considered a breaking site. || (!fOwnLine && !pElementLayout->_fSite); // If it's on its own line, and not first on line, FetchRun should have // terminated the line before we got here. // Assert( !( fOwnLine && !pfmtin->lsfgi.fFirstOnLine) ); pFlowLayout->GetSiteWidth(pLayout, pLS->_pci, pLS->_lsMode==CLineServices::LSMODE_MEASURER, pLS->_xWrappingWidth, &xWidth, &yHeight, &xMinWidth); // v-Dimension computed in VerticalAlignObjects // BUGBUG (cthrash) We have rounding errors in LS; don't pass zero objdim.heightsRef.dvAscent = 1; objdim.heightsRef.dvDescent = 0; objdim.heightsRef.dvMultiLineHeight = 1; if(_pLS->_fMinMaxPass) { objdim.heightsPres = objdim.heightsRef; } if(pLS->_fIsRuby && !pLS->_fIsRubyText) { pLS->_yMaxHeightForRubyBase = max(pLS->_yMaxHeightForRubyBase, yHeight); } // We need to store two widths in the dobj: The width corresponding to // the wrapping width (urColumnMax) and the minimum width. LsGetMinDur, // however, does not recognize two widths for ILS objects. We therefore // cache the difference, and account for these in an enumeration callback // after the LsGetMinDur pass. if(!pLS->_fMinMaxPass) { pdobj->_dvMinMaxDelta = 0; objdim.dur = xWidth; } else { pdobj->_dvMinMaxDelta = xWidth - xMinWidth; objdim.dur = xMinWidth; } if(pCF->HasCharGrid(TRUE)) { long lCharGridSize = pLS->GetCharGridSize(); pdobj->_dvMinMaxDelta = pLS->GetClosestGridMultiple(lCharGridSize, pdobj->_dvMinMaxDelta); objdim.dur = pLS->GetClosestGridMultiple(lCharGridSize, objdim.dur); } if(fOwnLine) { // If we are inside a something like say a PRE then too we do // not terminate, because if there was a \r right after the ownline site // then we will allow that \r to break the line. We do not check if the // subsequent char is a \r because there might be goop(comments, hidden // stuff etc etc) between this site and the \r. Hence here we just march // forward and if we run into text or layout later on we will terminate // the line then. This way we will eat up the goop if any in between. if(!pLS->_fScanForCR) { COneRun* porOut; COneRun* por = pLS->_listFree.GetFreeOneRun(plsrun); if(!por) { lserr = lserrOutOfMemory; goto Cleanup; } Assert(plsrun->IsNormalRun()); Assert(plsrun->_lscch == plsrun->_lscchOriginal); por->_lscpBase += plsrun->_lscch; // If this object has to be on its own line, then it clearly // ends the current line. lserr = pLS->TerminateLine(por, CLineServices::TL_ADDEOS, &porOut); if(lserr != lserrNone) { goto Cleanup; } // Free the one run pLS->_listFree.SpliceIn(por); } else { // Flip this bit so that we will setup pfmtres properly later on fOwnLine = FALSE; } // If we have an 'ownline' site, by definition this is a breaking // site, meaning we can (or more precisely should) break on either // side of the site. pdobj->_fIsBreakingSite = TRUE; // NOTE(SujalP): Bug 65906. // We originally used to set ourselves up to collect after space only // for morphed elements. As it turns out, we want to collect after space // from margins of _all_ ownline sites (including morphed elements), // because margins for ownline-sites are not accounted for in // VerticalAlignObjects (see CLayout::GetMarginInfo for more details -- // it returns 0 for ownline sites). pLS->_pNodeForAfterSpace = pNodeLayout; // All ownline sites have their x position to be 0 if(pElementLayout->HasFlag(TAGDESC_OWNLINE)) { pLayout->SetXProposed(0); } } if(fOwnLine) { *pfmtres = fmtrCompletedRun; } else { const long urWrappingWidth = max(pfmtin->lsfgi.urColumnMax, pLS->_xWrappingWidth); *pfmtres = (pfmtin->lsfgi.fFirstOnLine || pfmtin->lsfgi.urPen+objdim.dur<=urWrappingWidth)?fmtrCompletedRun:fmtrExceededMargin; } // This is an accessor to the dnode, telling LS to set the dnode pointing // to our dobj. lserr = LsdnFinishRegular(pLS->_plsc, cchSite, pfmtin->lsfrun.plsrun, pfmtin->lsfrun.plschp, (struct dobj*)pdobj, &objdim); Cleanup: return lserr; }
//+==================================================================================== // // Method: PositionChanged // // Synopsis: Hit the Layout for the size you should be and ask your adorner for it to give // you your position based on this // //------------------------------------------------------------------------------------ void CFocusAdorner::PositionChanged(const CSize* psize) { Assert(_pElement); Assert(_pElement->GetFirstBranch()); Assert(_pView->IsInState(CView::VS_OPEN)); if(_pDispNode) { CLayout* pLayout = _pElement->GetUpdatedNearestLayout(); CTreeNode* pTreeNode = _pElement->GetFirstBranch(); BOOL fRelative = pTreeNode->GetCharFormat()->_fRelative; CDispNode* pDispParent = _pDispNode->GetParentNode(); CDispNode* pDispNode = NULL; Assert(_pShape); // Get the display node which contains the element with focus // (If the focus display node is not yet anchored in the display tree, pretend the element // is not correct as well. After the focus display node is anchored, this routine will // get called again and can correctly associate the display nodes at that time.) if(pDispParent) { // BUGBUG: Move this logic down into GetElementDispNode (passing a flag so that GetElementDispNode // can distinguish between "find nearest" and "find exact" with this call being a "find nearest" // and virtually all others being a "find exact" (brendand) CElement* pDisplayElement = NULL; if(!pTreeNode->IsPositionStatic() || _pElement->HasLayout()) { pDisplayElement = _pElement; } else if(!fRelative) { pDisplayElement = pLayout->ElementOwner(); } else { CTreeNode* pDisplayNode = pTreeNode->GetCurrentRelativeNode(pLayout->ElementOwner()); Assert(pDisplayNode); // This should never be NULL, but be safe anyway if(pDisplayNode) { pDisplayElement = pDisplayNode->Element(); } } Assert(pDisplayElement); // This should never be NULL, but be safe anyway if(pDisplayElement) { pDispNode = pLayout->GetElementDispNode(pDisplayElement); } } // Verify that the display node which contains the element with focus and the focus display node // are both correctly anchored in the display tree (that is, have a common parent) // (If they do not, this routine will get called again once both get correctly anchored // after layout is completed) if(pDispNode) { CDispNode* pDispNodeTemp; for(pDispNodeTemp=pDispNode; pDispNodeTemp&&pDispNodeTemp!=pDispParent; pDispNodeTemp=pDispNodeTemp->GetParentNode()) ; if(!pDispNodeTemp) { pDispNode = NULL; } Assert(!pDispNode || pDispNodeTemp==pDispParent); } if(pDispNode) { if(!psize || _dnl!=DISPNODELAYER_FLOW) { CPoint ptFromOffset(_afxGlobalData._Zero.pt); CPoint ptToOffset(_afxGlobalData._Zero.pt); if(!_fTopLeftValid) { CRect rc; _pShape->GetBoundingRect(&rc); _pShape->OffsetShape(-rc.TopLeft().AsSize()); _ptTopLeft = rc.TopLeft(); if(!_pElement->HasLayout() && fRelative) { CPoint ptOffset; _pElement->GetUpdatedParentLayout()->GetFlowPosition(pDispNode, &ptOffset); _ptTopLeft -= ptOffset.AsSize(); } _fTopLeftValid = TRUE; } pDispNode->TransformPoint(&ptFromOffset, COORDSYS_CONTENT, COORDSYS_GLOBAL); _pDispNode->TransformPoint(&ptToOffset, COORDSYS_PARENT, COORDSYS_GLOBAL); _pDispNode->SetPosition(_ptTopLeft.AsSize()+(ptFromOffset-ptToOffset).AsPoint()); } else { CPoint pt = _pDispNode->GetPosition(); Assert(_fTopLeftValid); pt += *psize; _pDispNode->SetPosition(pt); } } // If the display node containing the element with focus is not correctly placed in the display // tree, remove the focus display node as well to prevent artifacts else { _pDispNode->ExtractFromTree(); } } }