LICE_IFont* IGraphics::CacheFont(IText* pTxt) { LICE_CachedFont* font = (LICE_CachedFont*)s_fontCache.Find(pTxt); if (!font) { font = new LICE_CachedFont; int h = pTxt->mSize; int esc = 10 * pTxt->mOrientation; int wt = (pTxt->mStyle == IText::kStyleBold ? FW_BOLD : FW_NORMAL); int it = (pTxt->mStyle == IText::kStyleItalic ? TRUE : FALSE); int q; if (pTxt->mQuality == IText::kQualityDefault) q = DEFAULT_QUALITY; #ifdef CLEARTYPE_QUALITY else if (pTxt->mQuality == IText::kQualityClearType) q = CLEARTYPE_QUALITY; else if (pTxt->mQuality == IText::kQualityAntiAliased) #else else if (pTxt->mQuality != IText::kQualityNonAntiAliased) #endif q = ANTIALIASED_QUALITY; else // if (pTxt->mQuality == IText::kQualityNonAntiAliased) q = NONANTIALIASED_QUALITY; #ifdef __APPLE__ bool resized = false; Resize: if (h < 2) h = 2; #endif HFONT hFont = CreateFont(h, 0, esc, esc, wt, it, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, q, DEFAULT_PITCH, pTxt->mFont); if (!hFont) { delete(font); return 0; } font->SetFromHFont(hFont, LICE_FONT_FLAG_OWNS_HFONT | LICE_FONT_FLAG_FORCE_NATIVE); #ifdef __APPLE__ if (!resized && font->GetLineHeight() != h) { h = int((double)(h * h) / (double)font->GetLineHeight() + 0.5); resized = true; goto Resize; } #endif s_fontCache.Add(font, pTxt); }
void SNM_DynSizedText::OnPaint(LICE_IBitmap *drawbm, int origin_x, int origin_y, RECT *cliprect) { RECT r = m_position; r.left += origin_x; r.right += origin_x; r.top += origin_y; r.bottom += origin_y; int h = r.bottom-r.top; int w = r.right-r.left; ColorTheme* ct = SNM_GetColorTheme(); int col = m_col; if (!col) col = ct ? LICE_RGBA_FROMNATIVE(ct->main_text, m_alpha) : LICE_RGBA(255,255,255,255); if (m_wantBorder) LICE_DrawRect(drawbm,r.left,r.top,w,h,col,0.2f); // title lane int laneHeight = GetTitleLaneHeight(); if (WantTitleLane() && HasTitleLane()) { if (m_wantBorder) LICE_Line(drawbm, r.left,r.top+laneHeight-1,r.right,r.top+laneHeight-1,col,0.2f); // title's band coloring (works for all themes) LICE_FillRect(drawbm,r.left,r.top,r.right-r.left,laneHeight,col,1.0f,LICE_BLIT_MODE_OVERLAY); LICE_FillRect(drawbm,r.left,r.top,r.right-r.left,laneHeight,col,1.0f,LICE_BLIT_MODE_OVERLAY); static LICE_CachedFont sFont; if (!sFont.GetHFont()) // single lazy init.. { LOGFONT lf = { SNM_FONT_HEIGHT, 0,0,0,FW_BOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,SNM_FONT_NAME }; sFont.SetFromHFont(CreateFontIndirect(&lf),LICE_FONT_FLAG_OWNS_HFONT|LICE_FONT_FLAG_FORCE_NATIVE); // others props are set on demand (support theme switches) } sFont.SetBkMode(TRANSPARENT); sFont.SetTextColor(LICE_RGBA_FROMNATIVE(WDL_STYLE_GetSysColor(COLOR_WINDOW), 255)); // "negative" color { RECT tr = {r.left,r.top,r.right,r.top+laneHeight}; char buf[64] = ""; _snprintfSafe(buf, sizeof(buf), " %s ", m_title.Get()); // trick for better display when left/right align sFont.DrawText(drawbm, buf, -1, &tr, DT_SINGLELINE|DT_NOPREFIX|DT_VCENTER|m_titleAlign); } // resize draw rect: take band into account r.top += laneHeight; h = r.bottom-r.top; } // ok, now the meat: render lines with a dynamic sized text if (!m_lines.GetSize() || !m_lines.Get(m_maxLineIdx)) return; /////////////////////////////////////////////////////////////////////////////// #ifndef _SNM_MISC // 1st sol.: full width but several fonts can be tried // initial font height estimation // touchy: the better estimation, the less cpu use! int estimFontH = int((w*2.65)/m_lines.Get(m_maxLineIdx)->GetLength()); // 2.65 = average from tests.. if (estimFontH > int(h/m_lines.GetSize())+0.5) estimFontH = int(h/m_lines.GetSize()+0.5); // check if the current font can do the job if (m_lastFontH>=SNM_FONT_HEIGHT && abs(estimFontH-m_lastFontH) < 2) // tolerance: 2 pixels { #ifdef _SNM_DYN_FONT_DEBUG OutputDebugString("SNM_DynSizedText::OnPaint() - Skip font creation\n"); #endif m_font.SetTextColor(col); DrawLines(drawbm, &r, m_lastFontH); } else { m_lastFontH = estimFontH; #ifdef _SNM_DYN_FONT_DEBUG int dbgTries=0; #endif while(m_lastFontH>SNM_FONT_HEIGHT) { HFONT lf = CreateFont(m_lastFontH,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,m_fontName.Get()); m_font.SetFromHFont(lf, LICE_FONT_FLAG_OWNS_HFONT|LICE_FONT_FLAG_FORCE_NATIVE); m_font.SetBkMode(TRANSPARENT); m_font.SetTextColor(col); RECT tr = {0,0,0,0}; // DT flags must be consistent with DrawLines() m_font.DrawText(NULL, m_lines.Get(m_maxLineIdx)->Get(), -1, &tr, DT_SINGLELINE|DT_BOTTOM|DT_NOPREFIX|DT_CALCRECT); if ((tr.right - tr.left) > (w-int(w*0.02+0.5))) // room: 2% of w { m_font.SetFromHFont(NULL,LICE_FONT_FLAG_OWNS_HFONT); DeleteObject(lf); m_lastFontH--; #ifdef _SNM_DYN_FONT_DEBUG dbgTries++; #endif } else { DrawLines(drawbm, &r, m_lastFontH); // no font deletion: will try to re-use it.. break; } } #ifdef _SNM_DYN_FONT_DEBUG char dbg[256]; _snprintfSafe(dbg, sizeof(dbg), "SNM_DynSizedText::OnPaint() - %d tries, estim: %d, real: %d\n", dbgTries, estimFontH, m_lastFontH); OutputDebugString(dbg); #endif } /////////////////////////////////////////////////////////////////////////////// #else // 2nd sol.: render text in best effort, single font creation /*JFB commented: truncated text.. int fontHeight = int((w*2.65)/m_lines.Get(m_maxLineIdx)->GetLength()); // 2.65 = average from tests.. if (fontHeight > int(h/m_lines.GetSize())+0.5) fontHeight = int(h/m_lines.GetSize()+0.5); */ // font height estimation (safe but it does not use all the available width/height) int fontHeight = int(h/m_lines.GetSize() + 0.5); while (fontHeight>SNM_FONT_HEIGHT && (fontHeight*m_lines.Get(m_maxLineIdx)->GetLength()*0.55) > w) // 0.55: h/w factor fontHeight--; if (fontHeight>=SNM_FONT_HEIGHT) { HFONT lf = CreateFont(fontHeight,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,m_fontName.Get()); m_font.SetFromHFont(lf, LICE_FONT_FLAG_OWNS_HFONT|LICE_FONT_FLAG_FORCE_NATIVE); m_font.SetBkMode(TRANSPARENT); m_font.SetTextColor(col); DrawLines(drawbm, &r, fontHeight); m_font.SetFromHFont(NULL,LICE_FONT_FLAG_OWNS_HFONT); DeleteObject(lf); } #endif }