int CFontPtr::Release() { CFont* p = NULL; klSwap(p, mp_Ref); int iRef = p ? p->Release() : 0; return iRef; }
bool CFontPtr::Attach(CFont* apRef) { if (apRef != mp_Ref) { klSwap(mp_Ref, apRef); if (mp_Ref) mp_Ref->AddRef(); SafeRelease(apRef); } return (mp_Ref != NULL); }
// Shrink lengths of [part1..part2] (including) // They must not exceed `right` X coordinate void CVConLine::DistributeParts(uint part1, uint part2, uint right) { if ((part1 > part2) || (part2 >= PartsCount)) { _ASSERTE((part1 <= part2) && (part2 < PartsCount)); return; } // If possible - shrink only last part // TRF_SizeFree - Spaces or horizontal frames. It does not matter, how many *real* characters we may write if ((TextParts[part2].Flags & TRF_SizeFree) && ((TextParts[part2].PositionX + MIN_SIZEFREE_WIDTH) < right) ) part1 = part2; if (right <= TextParts[part1].PositionX) { _ASSERTE(right > TextParts[part1].PositionX); return; } const uint suggMul = 4, suggDiv = 5; uint FontWidth2 = (FontWidth * 2); uint FontWidth2m = (FontWidth2 * suggMul / suggDiv); uint ReqWidth = (right - TextParts[part1].PositionX); // unused? uint FullWidth = (TextParts[part2].PositionX + TextParts[part2].TotalWidth - TextParts[part1].PositionX); // 1) shrink only TCF_WidthFree chars // 2) also shrink TCF_WidthDouble (if exist) a little // 3) shrink all possibilities WARNING("Change the algorithm"); // a) count all TCF_WidthFree, TCF_WidthNormal, TCF_WidthDouble separatedly // b) so we able to find most suitable way to shrink either part with its own factor (especially useful when both CJK and single-cell chars exists) VConTextPartWidth AllWidths[TCF_WidthLast] = {}; // Count all widths for parts and check if we may do shrink with TCF_WidthFree chars only bool bHasFreeOverlaps = HasFreeOverlaps(part1, part2, right, AllWidths); uint nAllWidths = (AllWidths[TCF_WidthFree].Width + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width); _ASSERTE(nAllWidths == FullWidth); // At the moment, they must match // What we may to shrink? if (nAllWidths <= ReqWidth) { if ((nAllWidths != ReqWidth) && !bHasFreeOverlaps) { DistributePartsFree(part1, part2, right); } else { _ASSERTE(FALSE && "Already fit, nothing to shrink"); } return; } // Only spaces and horizontal frames if (!bHasFreeOverlaps && ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width) <= ReqWidth) ) { DistributePartsFree(part1, part2, right); return; } uint nAllMin = AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].MinWidth + AllWidths[TCF_WidthDouble].MinWidth; if (!nAllMin) { _ASSERTE(nAllMin!=NULL); // Must not be zero! return; } // method and options uint nShrinkParts = (1 << TCF_WidthFree); if ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width) <= ReqWidth) { AllWidths[TCF_WidthFree].ReqWidth = ReqWidth - (AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width); } else if ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].MinWidth) <= ReqWidth) { // Spaces and double-space glyphs // Actually, with monospaced fonts we would have fit problems, // when double-space glyphs takes only one cell in console. // That is non-DBCS systems or UTF-8(?) on DBCS system nShrinkParts |= (1 << TCF_WidthDouble); AllWidths[TCF_WidthFree].ReqWidth = AllWidths[TCF_WidthFree].MinWidth; AllWidths[TCF_WidthDouble].ReqWidth = ReqWidth - (AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthFree].ReqWidth); } else { // Shrink all types nShrinkParts |= (1 << TCF_WidthNormal) | (1 << TCF_WidthDouble); // And we may apply a larger coefficient to dominating type of chars // Count each double-space glyph as 2 cells (preferred) AllWidths[TCF_WidthDouble].Count *= 2; // Count "all" cells int nAllCells = AllWidths[TCF_WidthDouble].Count + AllWidths[TCF_WidthNormal].Count + AllWidths[TCF_WidthFree].Count; // Sort types by cells used uint nMost = TCF_WidthFree; if ((AllWidths[TCF_WidthDouble].Count >= AllWidths[TCF_WidthNormal].Count) && (AllWidths[TCF_WidthDouble].Count >= AllWidths[TCF_WidthFree].Count)) nMost = TCF_WidthDouble; else if ((AllWidths[TCF_WidthNormal].Count >= AllWidths[TCF_WidthDouble].Count) && (AllWidths[TCF_WidthNormal].Count >= AllWidths[TCF_WidthFree].Count)) nMost = TCF_WidthNormal; uint nOther1 = (nMost != TCF_WidthDouble) ? TCF_WidthDouble : TCF_WidthNormal; uint nFlags = (1 << nMost) | (1 << nOther1); uint nOther2 = (!(nFlags & (1 << TCF_WidthDouble))) ? TCF_WidthDouble : (!(nFlags & (1 << TCF_WidthNormal))) ? TCF_WidthNormal : TCF_WidthFree; if (AllWidths[nOther1].Count < AllWidths[nOther2].Count) klSwap(nOther1, nOther2); uint nMostMul = (nMost == TCF_WidthDouble) ? 9 : 10; uint nMostDiv = 10; // Apply denominators AllWidths[nMost].ReqWidth = ReqWidth * AllWidths[nMost].Count * nMostMul / (nAllCells * nMostDiv); _ASSERTE(AllWidths[nMost].ReqWidth <= ReqWidth); // And prepare lesser types if ((ReqWidth - AllWidths[nMost].ReqWidth) >= (AllWidths[nOther1].Width + AllWidths[nOther2].MinWidth)) { AllWidths[nOther1].ReqWidth = AllWidths[nOther1].Width; AllWidths[nOther2].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth + AllWidths[nOther1].ReqWidth); } else if (AllWidths[nOther1].Count > 0 && AllWidths[nOther2].Count > 0) { _ASSERTE(AllWidths[nMost].Count > 0); AllWidths[nOther1].ReqWidth = ReqWidth * AllWidths[nOther1].Count / nAllCells; AllWidths[nOther2].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth + AllWidths[nOther1].ReqWidth); } else if (AllWidths[nOther1].Count > 0) { _ASSERTE(AllWidths[nMost].Count > 0 && AllWidths[nOther2].Count == 0); AllWidths[nOther1].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth); _ASSERTE(AllWidths[nOther2].Width == 0); AllWidths[nOther2].ReqWidth = 0; } else { _ASSERTE(AllWidths[nMost].Count > 0 && AllWidths[nOther1].Count == 0 && AllWidths[nOther2].Count == 0); _ASSERTE(AllWidths[nOther1].Width == 0 && AllWidths[nOther2].Width == 0); AllWidths[nOther1].ReqWidth = AllWidths[nOther2].ReqWidth = 0; } // Return *char* count AllWidths[TCF_WidthDouble].Count /= 2; } // Debug validations _ASSERTE((int)AllWidths[TCF_WidthFree].ReqWidth >= 0); _ASSERTE((int)AllWidths[TCF_WidthNormal].ReqWidth >= 0); _ASSERTE((int)AllWidths[TCF_WidthDouble].ReqWidth >= 0); // *Process* the shrink // Leftmost char coord uint PosX = TextParts[part1].PositionX; for (uint k = part1; k <= part2; k++) { VConTextPart& part = TextParts[k]; if (!part.Flags) { _ASSERTE(part.Flags); // Part must not be dropped yet! continue; } // Update new leftmost coord for this part part.PositionX = PosX; // Prepare loops TextCharType* pcf = part.CharFlags; // character flags (zero/free/normal/double) uint* pcw = part.CharWidth; // pointer to character width // Run part shrink part.TotalWidth = 0; if ((part.Flags & TRF_SizeFree) && (nShrinkParts & (1 << TCF_WidthFree))) { VConTextPartWidth& aw = AllWidths[TCF_WidthFree]; int iShrinkLeft = part.Length; _ASSERTE(AllWidths[TCF_WidthFree].Count>0); uint partReqWidth = (AllWidths[TCF_WidthFree].Count > 0) ? (aw.ReqWidth / AllWidths[TCF_WidthFree].Count) : 0; for (uint c = 0; c < part.Length; c++, pcf++, pcw++) { _ASSERTE(*pcf == TCF_WidthFree); DoShrink(*pcw, iShrinkLeft, partReqWidth, part.TotalWidth); } } else { for (uint c = 0; c < part.Length; c++, pcf++, pcw++) { if (nShrinkParts & (1 << *pcf)) { VConTextPartWidth& aw = AllWidths[*pcf]; DoShrink(*pcw, aw.Count, aw.ReqWidth, part.TotalWidth); } else { part.TotalWidth += *pcw; } } } PosX += part.TotalWidth; } // End of shrink (no more parts, no more methods) _ASSERTE(PosX <= right); }