void Font::initGDIFont() { if (!m_platformData.size()) { m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; return; } HWndDC hdc(0); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); TEXTMETRIC& textMetrics = metrics.otmTextMetrics; float ascent = textMetrics.tmAscent; float descent = textMetrics.tmDescent; float lineGap = textMetrics.tmExternalLeading; m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); m_avgCharWidth = textMetrics.tmAveCharWidth; m_maxCharWidth = textMetrics.tmMaxCharWidth; float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present. GLYPHMETRICS gm; static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &identity); if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) xHeight = gm.gmptGlyphOrigin.y; m_fontMetrics.setXHeight(xHeight); m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare); SelectObject(hdc, oldFont); }
int main(int argc, char **argv) { Py_Initialize(); PyImport_AppendInittab("spam", &PyInit_spam); PyRun_SimpleString("from time import time,ctime\n" "print('Today is', ctime(time()))\n"); PyRun_SimpleString("import spam\n" "xx = spam.SpamCall('abcd')\n" "print(xx)\n"); PyRun_SimpleString("with open('stackless.py') as ss: exec(ss.read())"); Py_Finalize(); ObjectPtrTable::Instance()->Init(10); TestObj stack_obj; TestObj *p_obj = new TestObj; ObjectHandler<TestObj> hda(stack_obj); ObjectHandler<TestObj> hdb(*p_obj); TestObj *stack_obj_ptr = hda.ToObject(); TestObj *heap_obj_ptr = hdb.ToObject(); delete p_obj; p_obj = new TestObj; ObjectHandler<TestObj> hdc(*p_obj); heap_obj_ptr = hdb.ToObject(); if (hdc == hdb) { return false; } else { TestObj *heap_obj_ptr_c = hdc.ToObject(); } return 0; }
// Return the height of system font |font| in pixels. We use this size by // default for some non-form-control elements. static float systemFontSize(const LOGFONT& font) { float size = -font.lfHeight; if (size < 0) { HFONT hFont = CreateFontIndirect(&font); if (hFont) { HWndDC hdc(0); // What about printing? Is this the right DC? if (hdc) { HGDIOBJ hObject = SelectObject(hdc, hFont); TEXTMETRIC tm; GetTextMetrics(hdc, &tm); SelectObject(hdc, hObject); size = tm.tmAscent; } DeleteObject(hFont); } } // The "codepage 936" bit here is from Gecko; apparently this helps make // fonts more legible in Simplified Chinese where the default font size is // too small. // // FIXME: http://b/1119883 Since this is only used for "small caption", // "menu", and "status bar" objects, I'm not sure how much this even // matters. Plus the Gecko patch went in back in 2002, and maybe this // isn't even relevant anymore. We should investigate whether this should // be removed, or perhaps broadened to be "any CJK locale". // return ((size < 12.0f) && (GetACP() == 936)) ? 12.0f : size; }
FontPlatformData::FontPlatformData(GDIObject<HFONT> font, float size, bool bold, bool oblique, bool useGDI) : m_font(SharedGDIObject<HFONT>::create(WTFMove(font))) , m_size(size) , m_orientation(Horizontal) , m_widthVariant(RegularWidth) , m_isColorBitmapFont(false) , m_syntheticBold(bold) , m_syntheticOblique(oblique) , m_useGDI(useGDI) { HWndDC hdc(0); SaveDC(hdc); ::SelectObject(hdc, m_font->get()); UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL); ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics."); if (bufferSize) { OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize); GetOutlineTextMetricsW(hdc, bufferSize, metrics); WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName); platformDataInit(m_font->get(), size, hdc, faceName); free(metrics); } RestoreDC(hdc, -1); }
void CMFC_DemoView::OnDraw(CDC* pDC) { CMFC_DemoDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 CClientDC hdc(this); SetMapMode(hdc, MM_ANISOTROPIC); //设置映像模式 HPEN hP = (HPEN)GetStockObject(BLACK_PEN); //黑色画笔 HBRUSH hB = (HBRUSH)GetStockObject(DKGRAY_BRUSH); //画刷 SelectObject(hdc, hB); //选择画刷 SelectObject(hdc, hP); //选择画笔 RoundRect(hdc, 50, 120, 100, 200, 15, 15); //绘制圆角矩形 hB = (HBRUSH)GetStockObject(LTGRAY_BRUSH); //采用亮灰色画刷 SelectObject(hdc, hB); //选择画刷 Ellipse(hdc, 150, 50, 200, 150); //绘制椭圆 hB = (HBRUSH)GetStockObject(HOLLOW_BRUSH); //虚画刷 SelectObject(hdc, hB); //选择画刷 Pie(hdc, 250, 50, 300, 100, 250, 50, 300, 50); //绘制饼形 hP = CreatePen(PS_DASHDOT, 1, RGB(0, 0, 255)); hB = CreateHatchBrush(HS_HORIZONTAL, RGB(0, 255, 0)); SelectObject(hdc, hP); SelectObject(hdc, hB); RoundRect(hdc, 35, 220, 115, 270, 15, 15); Ellipse(hdc, 125, 170, 225, 220); Pie(hdc, 250, 120, 300, 170, 300, 120, 300, 170); }
void display_number_t::measure_vertical(extents_t& calculated_horizontal, const place_data_t& placed_horizontal) { assert(window_m); place_data_t save_bounds; implementation::get_control_bounds(window_m, save_bounds); place_data_t static_bounds; top(static_bounds) = top(placed_horizontal); left(static_bounds) = left(placed_horizontal); width(static_bounds) = width(placed_horizontal); height(static_bounds) = 10000; // bottomless implementation::set_control_bounds(window_m, static_bounds); HDC hdc(::GetWindowDC(window_m)); std::string title(implementation::get_window_title(window_m)); std::wstring wtitle; to_utf16(title.begin(), title.end(), std::back_inserter(wtitle)); place_data_liukahr_t out_extent; // metrics::set_theme_name(L"Edit"); // // If we don't have the type of this widget, then we should return a // zero sized rectangle. This is usually correct, and a good assumption // anyway. // int uxtheme_type = EP_EDITTEXT; // // Get the text metrics (and calculate the baseline of this widget) // TEXTMETRIC widget_tm; bool have_tm = metrics::get_font_metrics(uxtheme_type, widget_tm); assert(have_tm); const place_data_liukahr_t in_extents = static_bounds; bool have_extents = metrics::get_text_extents(uxtheme_type, wtitle.c_str(), out_extent, &in_extents); assert(have_extents); extents_t::slice_t& vert = calculated_horizontal.vertical(); vert.length_m = height(out_extent); // set the baseline for the text metrics::set_window(window_m); if (have_tm) // distance from top to baseline vert.guide_set_m.push_back(widget_tm.tmHeight - widget_tm.tmDescent); implementation::set_control_bounds(window_m, save_bounds); }
static bool fontContainsCharacter(const FontPlatformData* fontData, const wchar_t* family, UChar32 character) { // FIXME: For non-BMP characters, GetFontUnicodeRanges is of // no use. We have to read directly from the cmap table of a font. // Return true for now. if (character > 0xFFFF) return true; // This cache is just leaked on shutdown. static FontCmapCache* fontCmapCache = 0; if (!fontCmapCache) fontCmapCache = new FontCmapCache; HashMap<const wchar_t*, icu::UnicodeSet*>::iterator it = fontCmapCache->find(family); if (it != fontCmapCache->end()) return it->value->contains(character); HFONT hfont = fontData->hfont(); HWndDC hdc(0); HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(hdc, hfont)); int count = GetFontUnicodeRanges(hdc, 0); if (!count && FontPlatformData::ensureFontLoaded(hfont)) count = GetFontUnicodeRanges(hdc, 0); if (!count) { WTF_LOG_ERROR("Unable to get the font unicode range after second attempt"); SelectObject(hdc, oldFont); return true; } static Vector<char, 512>* gGlyphsetBuffer = 0; if (!gGlyphsetBuffer) gGlyphsetBuffer = new Vector<char, 512>(); gGlyphsetBuffer->resize(GetFontUnicodeRanges(hdc, 0)); GLYPHSET* glyphset = reinterpret_cast<GLYPHSET*>(gGlyphsetBuffer->data()); // In addition, refering to the OS/2 table and converting the codepage list // to the coverage map might be faster. count = GetFontUnicodeRanges(hdc, glyphset); ASSERT(count > 0); SelectObject(hdc, oldFont); // FIXME: consider doing either of the following two: // 1) port back ICU 4.0's faster look-up code for UnicodeSet // 2) port Mozilla's CompressedCharMap or gfxSparseBitset unsigned i = 0; icu::UnicodeSet* cmap = new icu::UnicodeSet; while (i < glyphset->cRanges) { WCHAR start = glyphset->ranges[i].wcLow; cmap->add(start, start + glyphset->ranges[i].cGlyphs - 1); i++; } cmap->freeze(); // We don't lowercase |family| because all of them are under our control // and they're already lowercased. fontCmapCache->set(family, cmap); return cmap->contains(character); }
// This application exists to be connected to a console session while doing exactly nothing. // This keeps a console session alive and doesn't interfere with tests or other hooks. int __cdecl wmain(int /*argc*/, WCHAR* /*argv[]*/) { wil::unique_hdc hdc(CreateCompatibleDC(nullptr)); RETURN_LAST_ERROR_IF_NULL(hdc); LOGFONTW LogFont = { 0 }; LogFont.lfCharSet = DEFAULT_CHARSET; wcscpy_s(LogFont.lfFaceName, L"Terminal"); EnumFontFamiliesExW(hdc.get(), &LogFont, (FONTENUMPROC)FontEnumForV2Console, (LPARAM)hdc.get(), 0); return 0; }
LRESULT CFloatingWnd::OnPaint(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandled){ CPaintDC hdc(m_hWnd); CDC dcMem; dcMem.CreateCompatibleDC(hdc); hdc.SaveDC(); dcMem.SaveDC(); //select and draw dcMem.SelectBitmap(m_bmpBackground); hdc.BitBlt(0,0,m_size.cx,m_size.cy,dcMem,0,0,SRCCOPY); dcMem.RestoreDC(-1); hdc.RestoreDC(-1); return 0; }
// Converts |points| to pixels. One point is 1/72 of an inch. static float pointsToPixels(float points) { static float pixelsPerInch = 0.0f; if (!pixelsPerInch) { HWndDC hdc(0); // What about printing? Is this the right DC? if (hdc) // Can this ever actually be NULL? pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY); else pixelsPerInch = 96.0f; } static const float pointsPerInch = 72.0f; return points / pointsPerInch * pixelsPerInch; }
void CSVPDialog::OnPaint() { CPaintDC dc(this); // device context for painting CRect rcClient; GetClientRect(&rcClient); CMemoryDC hdc(&dc, rcClient); hdc.FillSolidRect(rcClient, m_bgColor); CRect rc; GetWindowRect(&rc); rc-=rc.TopLeft(); hdc.FrameRgn(&m_rgnBorder, &m_brushBorder,1,1); }
FloatRect Font::boundsForGDIGlyph(Glyph glyph) const { HWndDC hdc(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); GLYPHMETRICS gdiMetrics; static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); SelectObject(hdc, oldFont); return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, gdiMetrics.gmBlackBoxX + m_syntheticBoldOffset, gdiMetrics.gmBlackBoxY); }
float Font::widthForGDIGlyph(Glyph glyph) const { HWndDC hdc(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); GLYPHMETRICS gdiMetrics; static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity); float result = gdiMetrics.gmCellIncX + m_syntheticBoldOffset; SelectObject(hdc, oldFont); return result; }
void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) { HWndDC hdc(0); LOGFONT logFont; logFont.lfCharSet = DEFAULT_CHARSET; unsigned familyLength = min(familyName.length(), static_cast<unsigned>(LF_FACESIZE - 1)); memcpy(logFont.lfFaceName, familyName.characters(), familyLength * sizeof(UChar)); logFont.lfFaceName[familyLength] = 0; logFont.lfPitchAndFamily = 0; TraitsInFamilyProcData procData(familyName); EnumFontFamiliesEx(hdc, &logFont, traitsInFamilyEnumProc, reinterpret_cast<LPARAM>(&procData), 0); copyToVector(procData.m_traitsMasks, traitsMasks); }
PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const { HWndDC hdc(0); HGDIOBJ oldFont = SelectObject(hdc, hfont()); DWORD size = GetFontData(hdc, table, 0, 0, 0); RefPtr<SharedBuffer> buffer; if (size != GDI_ERROR) { buffer = SharedBuffer::create(size); DWORD result = GetFontData(hdc, table, 0, (PVOID)buffer->data(), size); ASSERT(result == size); } SelectObject(hdc, oldFont); return buffer.release(); }
static void OnPaint(HWND hwnd) { CRect r; CPaintDC hdc(hwnd); CWindow wnd(hwnd); wnd.GetClientRect(&r); HPEN hPen=CreatePen(PS_SOLID,0,config_bcolor2); LOGBRUSH lb={BS_SOLID,config_bcolor1}; HBRUSH hBrush=CreateBrushIndirect(&lb); HPEN hOldPen=hdc.SelectPen(hPen); HBRUSH hOldBrush=hdc.SelectBrush(hBrush); hdc.Rectangle(&r); hdc.SelectPen(hOldPen); hdc.SelectBrush(hOldBrush); DeleteObject(hPen); DeleteObject(hBrush); }
// Draws the Mandelbrot set void DrawSet(HWND hWnd) { // Get client area dimensions, which will be the image size RECT rect; GetClientRect(hWnd, &rect); int imageHeight(rect.bottom); int imageWidth(rect.right); // Create bitmap for one row of pixels in image HDC hdc(GetDC(hWnd)); // Get device context HDC memDC = CreateCompatibleDC(hdc); // Get device context to draw pixels HBITMAP bmp = CreateCompatibleBitmap(hdc, imageWidth, 1); HGDIOBJ oldBmp = SelectObject(memDC, bmp); // Selct bitmap into DC // Client area axes const double realMin(-2.1); // Minimum real value double imaginaryMin(-1.3); // Minimum imaginary value double imaginaryMax(+1.3); // Maximum imaginary value // Set maximum imaginary so axes are the same scale double realMax(realMin + (imaginaryMax - imaginaryMin)*imageWidth / imageHeight); // Get scale factors to convert pixel coordinates double realScale((realMax - realMin) / (imageWidth - 1)); double imaginaryScale((imaginaryMax - imaginaryMin) / (imageHeight - 1)); double cReal(0.0), cImaginary(0.0); // Stores c components double zReal(0.0), zImaginary(0.0); // Stores z components for (int y = 0 ; y < imageHeight ; ++y) { // Iterate over image rows zImaginary = cImaginary = imaginaryMax - y * imaginaryScale; for (int x = 0 ; x < imageWidth ; ++x) { // Iterate over pixels in a row zReal = cReal = realMin + x * realScale; // Set current pixel color based on n SetPixel(memDC, x, 0, Color(IteratePoint(zReal, zImaginary, cReal, cImaginary))); } // Transfer pixel row to client area device context BitBlt(hdc, 0, y, imageWidth, 1, memDC, 0, 0, SRCCOPY); } SelectObject(memDC, oldBmp); DeleteObject(bmp); // Delete bitmap DeleteDC(memDC); // and our working DC ReleaseDC(hWnd, hdc); // Release client area DC }
void Font::initGDIFont() { if (!m_platformData.size()) { m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; return; } HWndDC hdc(0); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); OUTLINETEXTMETRIC metrics; GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics); TEXTMETRIC& textMetrics = metrics.otmTextMetrics; float ascent, descent, lineGap; // The Open Font Format describes the OS/2 USE_TYPO_METRICS flag as follows: // "If set, it is strongly recommended to use OS/2.sTypoAscender - OS/2.sTypoDescender+ OS/2.sTypoLineGap as a value for default line spacing for this font." const UINT useTypoMetricsMask = 1 << 7; if (metrics.otmfsSelection & useTypoMetricsMask) { ascent = metrics.otmAscent; descent = metrics.otmDescent; lineGap = metrics.otmLineGap; } else { ascent = textMetrics.tmAscent; descent = textMetrics.tmDescent; lineGap = textMetrics.tmExternalLeading; } m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); m_avgCharWidth = textMetrics.tmAveCharWidth; m_maxCharWidth = textMetrics.tmMaxCharWidth; float xHeight = ascent * 0.56f; // Best guess for xHeight if no x glyph is present. GLYPHMETRICS gm; static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &identity); if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) xHeight = gm.gmptGlyphOrigin.y; m_fontMetrics.setXHeight(xHeight); m_fontMetrics.setUnitsPerEm(metrics.otmEMSquare); SelectObject(hdc, oldFont); }
void FenetreZoom::TracerZoom(wxRect &rSrc) { if (zoomInactif) return; ImageInfoCV* imAcq=fMere->ImAcq(); if (rSrc.GetHeight()<=0 || rSrc.GetWidth()<=0 || imAcq->cols<=0) return; if (rSrc.GetHeight()+rSrc.y>=imAcq->rows || rSrc.GetWidth()+rSrc.x>=imAcq->cols) return; wxImage *d=fMere->ImageAffichee(); wxClientDC hdc(this); hdc.SetBrush(*wxBLACK_BRUSH); wxRect src=rSrc; wxRect r=GetClientSize(); int zoomX =r.GetWidth()/rSrc.GetWidth()+1; int zoomY =r.GetHeight()/rSrc.GetHeight()+1; if (zoomX<zoomY) zoomY=zoomX; else zoomX=zoomY; if (zoomX*zoomY==0) return; wxRect dst(0,0,zoomX*rSrc.GetWidth(),zoomY*rSrc.GetHeight()); //SetClientSize(dst); hdc.DrawRectangle(r.GetRight(),r.GetTop(),r.GetRight(),r.GetBottom()); wxImage sousImage=d->GetSubImage(rSrc); // sousImage.SetMask(0); wxImage imageZoom=sousImage.Scale(dst.GetRight()-dst.GetLeft()+1,dst.GetBottom()-dst.GetTop()+1); // imageZoom.SetMask(0); wxBitmap b(imageZoom); hdc.DrawBitmap(b,0,0); hdc.SetPen(*wxBLACK); hdc.DrawRectangle(dst.GetRight(),r.GetTop(),r.GetRight(),r.GetBottom()); hdc.DrawRectangle(r.GetLeft(),dst.GetBottom(),r.GetRight(),r.GetBottom()); }
void FenetreZoom::TracerZoom(wxPoint p) { if (zoomInactif) { if (!IsShown()) return; zoomInactif =false; } ImageInfoCV* imAcq=fMere->ImAcq(); wxImage *d=fMere->ImageAffichee(); wxClientDC hdc(this); hdc.SetBrush(*wxBLACK_BRUSH); if (facteurZoom!=0) { if (imAcq && imAcq->cols>0) { wxRect src(0,0,imAcq->cols,imAcq->rows); wxRect dst=CalculPosRectDst(src,&p),r=GetClientSize(); hdc.DrawRectangle(r.GetRight(),r.GetTop(),r.GetRight(),r.GetBottom()); wxRect rSrc(src.GetLeft(),src.GetTop(),src.GetRight()-src.GetLeft()+1,src.GetBottom()-src.GetTop()+1); wxImage sousImage=d->GetSubImage(rSrc); // sousImage.SetMask(0); wxImage imageZoom=sousImage.Scale(dst.GetRight()-dst.GetLeft()+1,dst.GetBottom()-dst.GetTop()+1); // imageZoom.SetMask(0); wxBitmap b(imageZoom); hdc.DrawBitmap(b,0,0); hdc.SetPen(*wxBLACK); hdc.DrawRectangle(dst.GetRight(),r.GetTop(),r.GetRight(),r.GetBottom()); hdc.DrawRectangle(r.GetLeft(),dst.GetBottom(),r.GetRight(),r.GetBottom()); } } else { wxBitmap pub(*d); hdc.DrawBitmap(pub,-p.x,-p.y); } }
FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const { HWndDC hdc(0); SetGraphicsMode(hdc, GM_ADVANCED); HGDIOBJ oldFont = SelectObject(hdc, m_platformData.hfont()); GLYPHMETRICS gdiMetrics; static const MAT2 identity = { 0, 1, 0, 0, 0, 0, 0, 1 }; if (GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity) == -1) { if (FontPlatformData::ensureFontLoaded(m_platformData.hfont())) { // Retry GetTextMetrics. // FIXME: Handle gracefully the error if this call also fails. // See http://crbug.com/6401. if (GetGlyphOutline(hdc, glyph, GGO_METRICS | GGO_GLYPH_INDEX, &gdiMetrics, 0, 0, &identity) == -1) LOG_ERROR("Unable to get the glyph metrics after second attempt"); } } SelectObject(hdc, oldFont); return FloatRect(gdiMetrics.gmptGlyphOrigin.x, -gdiMetrics.gmptGlyphOrigin.y, gdiMetrics.gmBlackBoxX, gdiMetrics.gmBlackBoxY); }
void CPlayerToolBar::OnPaint() { //LONGLONG startTime = AfxGetMyApp()->GetPerfCounter(); CPaintDC dc(this); // device context for painting CRect paintRect(dc.m_ps.rcPaint); AppSettings& s = AfxGetAppSettings(); CRect rcClient; GetClientRect(&rcClient); CMemoryDC hdc(&dc, rcClient); hdc.SetBkMode(TRANSPARENT); CRect rc; GetWindowRect(&rc); if( paintRect == m_btnVolBG->m_rcHitest){ m_btnVolBG->OnPaint( &hdc, rc); m_btnVolTm->OnPaint( &hdc, rc); return; } CRect rcBottomSqu = rcClient; rcBottomSqu.top = rcBottomSqu.bottom - 10; CRect rcUpperSqu = rcClient; CMainFrame* pFrame = ((CMainFrame*)AfxGetMainWnd()); if (s.skinid == ID_SKIN_FIRST) hdc.FillSolidRect(rcUpperSqu, s.GetColorFromTheme(_T("ToolBarBG"), NEWUI_COLOR_TOOLBAR_UPPERBG)); else { CBitmap* cbm = CBitmap::FromHandle(pFrame->m_btoolbarbg); CDC bmpDc; bmpDc.CreateCompatibleDC(&hdc); HBITMAP oldhbm = (HBITMAP)bmpDc.SelectObject(cbm); BITMAP btmp; cbm->GetBitmap(&btmp); hdc.StretchBlt(0, 0, rcUpperSqu.Width(), rcUpperSqu.Height(), &bmpDc, 0, 0, btmp.bmWidth, btmp.bmHeight - 2, SRCCOPY); bmpDc.SelectObject(oldhbm); } HFONT holdft = NULL; if (m_adctrl.GetVisible()) holdft = (HFONT)hdc.SelectObject(m_adsft); else holdft = (HFONT)hdc.SelectObject(m_statft); hdc.SetTextColor(s.GetColorFromTheme(_T("ToolBarTimeText"), 0xffffff) ); UpdateButtonStat(); int volume = min( m_volctrl.GetPos() , m_volctrl.GetRangeMax() ); m_btnVolTm->m_rcHitest.MoveToXY(m_btnVolBG->m_rcHitest.left + ( m_btnVolBG->m_rcHitest.Width() * volume / m_volctrl.GetRangeMax() ) - m_btnVolTm->m_rcHitest.Width()/2 , m_btnVolBG->m_rcHitest.top + (m_btnVolBG->m_rcHitest.Height() - m_btnVolTm->m_rcHitest.Height() ) / 2 ); m_btnList.PaintAll(&hdc, rc); std::wstring sTimeBtnString = m_adctrl.GetCurAd(); if (!sTimeBtnString.empty()) { int prom_margin = 8; CSize size = dc.GetTextExtent(sTimeBtnString.c_str()); CSUIButton* cbtn = m_btnList.GetButton(L"SHARE"); if (cbtn && cbtn->m_currenthide) { cbtn = m_btnList.GetButton(L"LOGO"); if (cbtn && !cbtn->m_currenthide) prom_margin = -10; } if (cbtn && cbtn->m_currenthide) cbtn = NULL; CRect btnrc(prom_margin, 0, 0, 0); if (cbtn) { btnrc = cbtn->m_rcHitest - rc.TopLeft(); btnrc.left = btnrc.right + prom_margin; } int width = m_btnList.GetRelativeMinLength(rc, cbtn) - prom_margin; if (cbtn) width -= cbtn->m_rcHitest.Width(); if (width < 30) width = 0; if (size.cx > 0) btnrc.right = btnrc.left + width;//min(width, size.cx); else btnrc.right = btnrc.left; //btnrc.right -= 5; btnrc.top = (rc.Height() - size.cy) / 2; btnrc.bottom = btnrc.top + size.cy; m_adctrl.SetRect(btnrc, &hdc); m_adctrl.Paint(&hdc); } hdc.SelectObject(holdft); }
static bool PrintToDevice(const PrintData &pd, ProgressUpdateUI *progressUI = nullptr, AbortCookieManager *abortCookie = nullptr) { AssertCrash(pd.engine); if (!pd.engine) return false; AssertCrash(pd.printerName); if (!pd.printerName) return false; BaseEngine &engine = *pd.engine; ScopedMem<WCHAR> fileName; DOCINFO di = { 0 }; di.cbSize = sizeof(DOCINFO); if (gPluginMode) { fileName.Set(url::GetFileName(gPluginURL)); // fall back to a generic "filename" instead of the more confusing temporary filename di.lpszDocName = fileName ? fileName : L"filename"; } else di.lpszDocName = engine.FileName(); int current = 1, total = 0; if (pd.sel.Count() == 0) { for (size_t i = 0; i < pd.ranges.Count(); i++) { if (pd.ranges.At(i).nToPage < pd.ranges.At(i).nFromPage) total += pd.ranges.At(i).nFromPage - pd.ranges.At(i).nToPage + 1; else total += pd.ranges.At(i).nToPage - pd.ranges.At(i).nFromPage + 1; } } else { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { if (!BoundSelectionOnPage(pd.sel, pageNo).IsEmpty()) total++; } } AssertCrash(total > 0); if (0 == total) return false; if (progressUI) progressUI->UpdateProgress(current, total); // cf. http://blogs.msdn.com/b/oldnewthing/archive/2012/11/09/10367057.aspx ScopeHDC hdc(CreateDC(nullptr, pd.printerName, nullptr, pd.devMode)); if (!hdc) return false; if (StartDoc(hdc, &di) <= 0) return false; // MM_TEXT: Each logical unit is mapped to one device pixel. // Positive x is to the right; positive y is down. SetMapMode(hdc, MM_TEXT); const SizeI paperSize(GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT)); const RectI printable(GetDeviceCaps(hdc, PHYSICALOFFSETX), GetDeviceCaps(hdc, PHYSICALOFFSETY), GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES)); const float dpiFactor = std::min(GetDeviceCaps(hdc, LOGPIXELSX) / engine.GetFileDPI(), GetDeviceCaps(hdc, LOGPIXELSY) / engine.GetFileDPI()); bool bPrintPortrait = paperSize.dx < paperSize.dy; if (pd.devMode && (pd.devMode.Get()->dmFields & DM_ORIENTATION)) bPrintPortrait = DMORIENT_PORTRAIT == pd.devMode.Get()->dmOrientation; if (pd.sel.Count() > 0) { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { RectD bounds = BoundSelectionOnPage(pd.sel, pageNo); if (bounds.IsEmpty()) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); geomutil::SizeT<float> bSize = bounds.Size().Convert<float>(); float zoom = std::min((float)printable.dx / bSize.dx, (float)printable.dy / bSize.dy); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale) zoom = std::min(dpiFactor, zoom); else if (PrintScaleNone == pd.advData.scale) zoom = dpiFactor; for (size_t i = 0; i < pd.sel.Count(); i++) { if (pd.sel.At(i).pageNo != pageNo) continue; RectD *clipRegion = &pd.sel.At(i).rect; PointI offset((int)((clipRegion->x - bounds.x) * zoom), (int)((clipRegion->y - bounds.y) * zoom)); if (pd.advData.scale != PrintScaleNone) { // center the selection on the physical paper offset.x += (int)(printable.dx - bSize.dx * zoom) / 2; offset.y += (int)(printable.dy - bSize.dy * zoom) / 2; } bool ok = false; short shrink = 1; do { RenderedBitmap *bmp = engine.RenderBitmap( pd.sel.At(i).pageNo, zoom / shrink, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : nullptr); if (abortCookie) abortCookie->Clear(); if (bmp && bmp->GetBitmap()) { RectI rc(offset.x, offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); ok = bmp->StretchDIBits(hdc, rc); } delete bmp; shrink *= 2; } while (!ok && shrink < 32 && !(progressUI && progressUI->WasCanceled())); } // TODO: abort if !ok? if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } EndDoc(hdc); return false; } // print all the pages the user requested for (size_t i = 0; i < pd.ranges.Count(); i++) { int dir = pd.ranges.At(i).nFromPage > pd.ranges.At(i).nToPage ? -1 : 1; for (DWORD pageNo = pd.ranges.At(i).nFromPage; pageNo != pd.ranges.At(i).nToPage + dir; pageNo += dir) { if ((PrintRangeEven == pd.advData.range && pageNo % 2 != 0) || (PrintRangeOdd == pd.advData.range && pageNo % 2 == 0)) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); geomutil::SizeT<float> pSize = engine.PageMediabox(pageNo).Size().Convert<float>(); int rotation = 0; // Turn the document by 90 deg if it isn't in portrait mode if (pSize.dx > pSize.dy) { rotation += 90; std::swap(pSize.dx, pSize.dy); } // make sure not to print upside-down rotation = (rotation % 180) == 0 ? 0 : 270; // finally turn the page by (another) 90 deg in landscape mode if (!bPrintPortrait) { rotation = (rotation + 90) % 360; std::swap(pSize.dx, pSize.dy); } // dpiFactor means no physical zoom float zoom = dpiFactor; // offset of the top-left corner of the page from the printable area // (negative values move the page into the left/top margins, etc.); // offset adjustments are needed because the GDI coordinate system // starts at the corner of the printable area and we rather want to // center the page on the physical paper (except for PrintScaleNone // where the page starts at the very top left of the physical paper so // that printing forms/labels of varying size remains reliably possible) PointI offset(printable.x, printable.y); if (pd.advData.scale != PrintScaleNone) { // make sure to fit all content into the printable area when scaling // and the whole document page on the physical paper RectD rect = engine.PageContentBox(pageNo, Target_Print); geomutil::RectT<float> cbox = engine.Transform(rect, pageNo, 1.0, rotation).Convert<float>(); zoom = std::min((float)printable.dx / cbox.dx, std::min((float)printable.dy / cbox.dy, std::min((float)paperSize.dx / pSize.dx, (float)paperSize.dy / pSize.dy))); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale && dpiFactor < zoom) zoom = dpiFactor; // center the page on the physical paper offset.x += (int)(paperSize.dx - pSize.dx * zoom) / 2; offset.y += (int)(paperSize.dy - pSize.dy * zoom) / 2; // make sure that no content lies in the non-printable paper margins geomutil::RectT<float> onPaper(printable.x + offset.x + cbox.x * zoom, printable.y + offset.y + cbox.y * zoom, cbox.dx * zoom, cbox.dy * zoom); if (onPaper.x < printable.x) offset.x += (int)(printable.x - onPaper.x); else if (onPaper.BR().x > printable.BR().x) offset.x -= (int)(onPaper.BR().x - printable.BR().x); if (onPaper.y < printable.y) offset.y += (int)(printable.y - onPaper.y); else if (onPaper.BR().y > printable.BR().y) offset.y -= (int)(onPaper.BR().y - printable.BR().y); } bool ok = false; short shrink = 1; do { RenderedBitmap *bmp = engine.RenderBitmap(pageNo, zoom / shrink, rotation, nullptr, Target_Print, abortCookie ? &abortCookie->cookie : nullptr); if (abortCookie) abortCookie->Clear(); if (bmp && bmp->GetBitmap()) { RectI rc(offset.x, offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); ok = bmp->StretchDIBits(hdc, rc); } delete bmp; shrink *= 2; } while (!ok && shrink < 32 && !(progressUI && progressUI->WasCanceled())); // TODO: abort if !ok? if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } } EndDoc(hdc); return true; }
STDMETHODIMP CompositeOverlayImpl<B>::ModernRender(long _hdc) { short count = 0; Count(&count); for (int i=count-1; i>=0; i--) { IOverlay *pItem; Item(CComVariant(i), &pItem); VARIANT_BOOL vis; pItem->get_Visible(&vis); if (vis) { ISimpleOverlay2 *pISO2 = NULL; HRESULT hr = pItem->QueryInterface(__uuidof(ISimpleOverlay2), (void **)&pISO2); if (SUCCEEDED(hr)) { IOverlay *effectOverlay; pISO2->get_EffectOverlay(&effectOverlay); long effect; pISO2->get_EffectOverlayEffect(&effect); if (!effectOverlay) { pItem->Render(_hdc); } else { // prevent recursion pISO2->put_EffectOverlay(NULL); // Create a private HDC to draw into so that we can mask it. long width = 128; long height = 128; model->get_Width(&width); model->get_Height(&height); HDCImage hdc((HDC)_hdc, width, height); // Render the item pItem->Render(hdc); // Now mask it HDCImage hdcMask((HDC)hdc, width, height); effectOverlay->Render(hdcMask); switch(effect) { case 0: hdc.MaskOut(hdcMask); break; case 1: hdc.MaskIn(hdcMask); break; } // Copy private HDC into the passed HDC Graphics g((HDC)_hdc); g.DrawImage( &hdc.GetImage(), Rect(0, 0, width, height), // Destination rectangle 0, // Source rectangle X 0, // Source rectangle Y width, // Source rectangle width height, // Source rectangle height UnitPixel); // Reset recursion avoider pISO2->put_EffectOverlay(effectOverlay); } pISO2->Release(); } else pItem->Render(_hdc); } pItem->Release(); } return S_OK; }
STDMETHODIMP CompositeOverlayImpl<B>::Render(long _hdc) { short count = 0; Count(&count); REAL el[6]; CumulativeTransform(el); Matrix matrix(el[0], el[1], el[2], el[3], el[4], el[5]); // Firstly, if us or our parents don't transform the coordinate space, life is simple. if (matrix.IsIdentity()) { ModernRender(_hdc); } else { // Check if all children are of type ISimpleOverlay2 bool iso2 = true; for (int i=count-1; i>=0; i--) { IOverlay *pItem; Item(CComVariant(i), &pItem); VARIANT_BOOL vis; pItem->get_Visible(&vis); if (vis) { ISimpleOverlay2 *pISO2 = NULL; HRESULT hr = pItem->QueryInterface(__uuidof(ISimpleOverlay2), (void **)&pISO2); if (!SUCCEEDED(hr)) iso2 = false; else pISO2->Release(); } pItem->Release(); } // If all children are of type ISimpleOverlay2, life is also simple. if (iso2) { ModernRender(_hdc); } else { // Otherwise, draw into a pre-transformed hdc. long width = 128; long height = 128; model->get_Width(&width); model->get_Height(&height); HDCImage hdc((HDC)_hdc, width, height); for (int i=count-1; i>=0; i--) { IOverlay *pItem; Item(CComVariant(i), &pItem); VARIANT_BOOL vis; pItem->get_Visible(&vis); if (vis) pItem->Render(hdc); pItem->Release(); } Graphics g((HDC)_hdc); g.SetInterpolationMode(InterpolationModeHighQuality); g.SetSmoothingMode(SmoothingModeAntiAlias); g.MultiplyTransform(&matrix); g.DrawImage(&hdc.GetImage(), 0, 0); } } return S_OK; }
static bool PrintToDevice(PrintData& pd, ProgressUpdateUI *progressUI=NULL, AbortCookieManager *abortCookie=NULL) { AssertCrash(pd.engine); if (!pd.engine) return false; AssertCrash(pd.printerName); if (!pd.printerName) return false; BaseEngine& engine = *pd.engine; ScopedMem<WCHAR> fileName; DOCINFO di = { 0 }; di.cbSize = sizeof (DOCINFO); if (gPluginMode) { fileName.Set(ExtractFilenameFromURL(gPluginURL)); // fall back to a generic "filename" instead of the more confusing temporary filename di.lpszDocName = fileName ? fileName : L"filename"; } else di.lpszDocName = engine.FileName(); int current = 1, total = 0; if (pd.sel.Count() == 0) { for (size_t i = 0; i < pd.ranges.Count(); i++) { if (pd.ranges.At(i).nToPage < pd.ranges.At(i).nFromPage) total += pd.ranges.At(i).nFromPage - pd.ranges.At(i).nToPage + 1; else total += pd.ranges.At(i).nToPage - pd.ranges.At(i).nFromPage + 1; } } else { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { if (!BoundSelectionOnPage(pd.sel, pageNo).IsEmpty()) total++; } } AssertCrash(total > 0); if (0 == total) return false; if (progressUI) progressUI->UpdateProgress(current, total); // cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1882 // According to our crash dumps, Cannon printer drivers (caprenn.dll etc.) // are buggy and like to crash during printing with DEP violation // We disable dep during printing to hopefully not crash // TODO: even better would be to print in a separate process so that // crashes during printing wouldn't affect the main process. It's also // much more complicated to implement ScopeDisableDEP scopeNoDEP; // cf. http://blogs.msdn.com/b/oldnewthing/archive/2012/11/09/10367057.aspx ScopeHDC hdc(CreateDC(pd.driverName, pd.printerName, pd.portName, pd.devMode)); if (!hdc) return false; if (StartDoc(hdc, &di) <= 0) return false; // MM_TEXT: Each logical unit is mapped to one device pixel. // Positive x is to the right; positive y is down. SetMapMode(hdc, MM_TEXT); const SizeI paperSize(GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT)); const RectI printable(GetDeviceCaps(hdc, PHYSICALOFFSETX), GetDeviceCaps(hdc, PHYSICALOFFSETY), GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES)); const float dpiFactor = min(GetDeviceCaps(hdc, LOGPIXELSX) / engine.GetFileDPI(), GetDeviceCaps(hdc, LOGPIXELSY) / engine.GetFileDPI()); bool bPrintPortrait = paperSize.dx < paperSize.dy; if (pd.devMode && (pd.devMode.Get()->dmFields & DM_ORIENTATION)) bPrintPortrait = DMORIENT_PORTRAIT == pd.devMode.Get()->dmOrientation; if (pd.sel.Count() > 0) { for (int pageNo = 1; pageNo <= engine.PageCount(); pageNo++) { RectD bounds = BoundSelectionOnPage(pd.sel, pageNo); if (bounds.IsEmpty()) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); SizeT<float> bSize = bounds.Size().Convert<float>(); float zoom = min((float)printable.dx / bSize.dx, (float)printable.dy / bSize.dy); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale) zoom = min(dpiFactor, zoom); else if (PrintScaleNone == pd.advData.scale) zoom = dpiFactor; for (size_t i = 0; i < pd.sel.Count(); i++) { if (pd.sel.At(i).pageNo != pageNo) continue; RectD *clipRegion = &pd.sel.At(i).rect; PointI offset((int)((clipRegion->x - bounds.x) * zoom), (int)((clipRegion->y - bounds.y) * zoom)); if (!pd.advData.asImage) { RectI rc((int)(printable.dx - bSize.dx * zoom) / 2 + offset.x, (int)(printable.dy - bSize.dy * zoom) / 2 + offset.y, (int)(clipRegion->dx * zoom), (int)(clipRegion->dy * zoom)); engine.RenderPage(hdc, rc, pd.sel.At(i).pageNo, zoom, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); } else { RenderedBitmap *bmp = NULL; short shrink = 1; do { bmp = engine.RenderBitmap(pd.sel.At(i).pageNo, zoom / shrink, pd.rotation, clipRegion, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); if (!bmp || !bmp->GetBitmap()) { shrink *= 2; delete bmp; bmp = NULL; } } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled())); if (bmp) { RectI rc((int)(paperSize.dx - bSize.dx * zoom) / 2 + offset.x, (int)(paperSize.dy - bSize.dy * zoom) / 2 + offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); bmp->StretchDIBits(hdc, rc); delete bmp; } } } if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } EndDoc(hdc); return false; } // print all the pages the user requested for (size_t i = 0; i < pd.ranges.Count(); i++) { int dir = pd.ranges.At(i).nFromPage > pd.ranges.At(i).nToPage ? -1 : 1; for (DWORD pageNo = pd.ranges.At(i).nFromPage; pageNo != pd.ranges.At(i).nToPage + dir; pageNo += dir) { if ((PrintRangeEven == pd.advData.range && pageNo % 2 != 0) || (PrintRangeOdd == pd.advData.range && pageNo % 2 == 0)) continue; if (progressUI) progressUI->UpdateProgress(current, total); StartPage(hdc); SizeT<float> pSize = engine.PageMediabox(pageNo).Size().Convert<float>(); int rotation = 0; // Turn the document by 90 deg if it isn't in portrait mode if (pSize.dx > pSize.dy) { rotation += 90; swap(pSize.dx, pSize.dy); } // make sure not to print upside-down rotation = (rotation % 180) == 0 ? 0 : 270; // finally turn the page by (another) 90 deg in landscape mode if (!bPrintPortrait) { rotation = (rotation + 90) % 360; swap(pSize.dx, pSize.dy); } // dpiFactor means no physical zoom float zoom = dpiFactor; // offset of the top-left corner of the page from the printable area // (negative values move the page into the left/top margins, etc.); // offset adjustments are needed because the GDI coordinate system // starts at the corner of the printable area and we rather want to // center the page on the physical paper (default behavior) PointI offset(-printable.x, -printable.y); if (pd.advData.scale != PrintScaleNone) { // make sure to fit all content into the printable area when scaling // and the whole document page on the physical paper RectD rect = engine.PageContentBox(pageNo, Target_Print); RectT<float> cbox = engine.Transform(rect, pageNo, 1.0, rotation).Convert<float>(); zoom = min((float)printable.dx / cbox.dx, min((float)printable.dy / cbox.dy, min((float)paperSize.dx / pSize.dx, (float)paperSize.dy / pSize.dy))); // use the correct zoom values, if the page fits otherwise // and the user didn't ask for anything else (default setting) if (PrintScaleShrink == pd.advData.scale && dpiFactor < zoom) zoom = dpiFactor; // make sure that no content lies in the non-printable paper margins RectT<float> onPaper((paperSize.dx - pSize.dx * zoom) / 2 + cbox.x * zoom, (paperSize.dy - pSize.dy * zoom) / 2 + cbox.y * zoom, cbox.dx * zoom, cbox.dy * zoom); if (onPaper.x < printable.x) offset.x += (int)(printable.x - onPaper.x); else if (onPaper.BR().x > printable.BR().x) offset.x -= (int)(onPaper.BR().x - printable.BR().x); if (onPaper.y < printable.y) offset.y += (int)(printable.y - onPaper.y); else if (onPaper.BR().y > printable.BR().y) offset.y -= (int)(onPaper.BR().y - printable.BR().y); } if (!pd.advData.asImage) { RectI rc = RectI::FromXY((int)(paperSize.dx - pSize.dx * zoom) / 2 + offset.x, (int)(paperSize.dy - pSize.dy * zoom) / 2 + offset.y, paperSize.dx, paperSize.dy); engine.RenderPage(hdc, rc, pageNo, zoom, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); } else { RenderedBitmap *bmp = NULL; short shrink = 1; do { bmp = engine.RenderBitmap(pageNo, zoom / shrink, rotation, NULL, Target_Print, abortCookie ? &abortCookie->cookie : NULL); if (abortCookie) abortCookie->Clear(); if (!bmp || !bmp->GetBitmap()) { shrink *= 2; delete bmp; bmp = NULL; } } while (!bmp && shrink < 32 && !(progressUI && progressUI->WasCanceled())); if (bmp) { RectI rc((paperSize.dx - bmp->Size().dx * shrink) / 2 + offset.x, (paperSize.dy - bmp->Size().dy * shrink) / 2 + offset.y, bmp->Size().dx * shrink, bmp->Size().dy * shrink); bmp->StretchDIBits(hdc, rc); delete bmp; } } if (EndPage(hdc) <= 0 || progressUI && progressUI->WasCanceled()) { AbortDoc(hdc); return false; } current++; } } EndDoc(hdc); return true; }
// Draws the Mandelbrot set void DrawSetParallel(HWND hWnd) { HDC hdc(GetDC(hWnd)); // Get device context // Get client area dimensions, which will be the image size RECT rect; GetClientRect(hWnd, &rect); int imageHeight(rect.bottom); int imageWidth(rect.right); // Create bitmap for one row of pixels in image HDC memDC1 = CreateCompatibleDC(hdc); // Get device context to draw pixels HDC memDC2 = CreateCompatibleDC(hdc); // Get device context to draw pixels HBITMAP bmp1 = CreateCompatibleBitmap(hdc, imageWidth, 1); HBITMAP bmp2 = CreateCompatibleBitmap(hdc, imageWidth, 1); HGDIOBJ oldBmp1 = SelectObject(memDC1, bmp1); // Select bitmap into DC1 HGDIOBJ oldBmp2 = SelectObject(memDC2, bmp2); // Select bitmap into DC2 // Client area axes const double realMin(-2.1); // Minimum real value double imaginaryMin(-1.3); // Minimum imaginary value double imaginaryMax(+1.3); // Maximum imaginary value // Set maximum imaginary so axes are the same scale double realMax(realMin + (imaginaryMax - imaginaryMin)*imageWidth / imageHeight); // Get scale factors to convert pixel coordinates double realScale((realMax - realMin) / (imageWidth - 1)); double imaginaryScale((imaginaryMax - imaginaryMin) / (imageHeight - 1)); // Lambda expression to create an image row std::function<void(HDC&, int)> rowCalc = [&](HDC & memDC, int yLocal) { double zReal(0.0), cReal(0.0); double zImaginary(imaginaryMax - yLocal * imaginaryScale); double cImaginary(zImaginary); for (int x = 0 ; x < imageWidth ; ++x) { // Iterate over pixels in a row zReal = cReal = realMin + x * realScale; // Set current pixel color based on n SetPixel(memDC, x, 0, Color(IteratePoint(zReal, zImaginary, cReal, cImaginary))); } }; for (int y = 1 ; y < imageHeight ; y += 2) { // Iterate over image rows Concurrency::parallel_invoke([&] {rowCalc(memDC1, y - 1);}, [&] {rowCalc(memDC2, y);}); // Transfer pixel row to client area device context BitBlt(hdc, 0, y - 1, imageWidth, 1, memDC1, 0, 0, SRCCOPY); BitBlt(hdc, 0, y, imageWidth, 1, memDC2, 0, 0, SRCCOPY); } // If there's an odd number of rows, take care of the last one if (imageHeight % 2 == 1) { rowCalc(memDC1, imageWidth - 1); BitBlt(hdc, 0, imageHeight - 1, imageWidth, 1, memDC1, 0, 0, SRCCOPY); } SelectObject(memDC1, oldBmp1); SelectObject(memDC2, oldBmp2); DeleteObject(bmp1); // Delete bitmap 1 DeleteObject(bmp2); // Delete bitmap 2 DeleteDC(memDC1); // and our working DC 1 DeleteDC(memDC2); // and our working DC 2 ReleaseDC(hWnd, hdc); // and client area DC }
bool UniscribeController::shapeAndPlaceItem(const UChar* cp, unsigned i, const Font* fontData, GlyphBuffer* glyphBuffer) { // Determine the string for this item. const UChar* str = cp + m_items[i].iCharPos; int len = m_items[i+1].iCharPos - m_items[i].iCharPos; SCRIPT_ITEM item = m_items[i]; // Set up buffers to hold the results of shaping the item. Vector<WORD> glyphs; Vector<WORD> clusters; Vector<SCRIPT_VISATTR> visualAttributes; clusters.resize(len); // Shape the item. // The recommended size for the glyph buffer is 1.5 * the character length + 16 in the uniscribe docs. // Apparently this is a good size to avoid having to make repeated calls to ScriptShape. glyphs.resize(1.5 * len + 16); visualAttributes.resize(glyphs.size()); if (!shape(str, len, item, fontData, glyphs, clusters, visualAttributes)) return true; // We now have a collection of glyphs. Vector<GOFFSET> offsets; Vector<int> advances; offsets.resize(glyphs.size()); advances.resize(glyphs.size()); int glyphCount = 0; HRESULT placeResult = ScriptPlace(0, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(), &item.a, advances.data(), offsets.data(), 0); if (placeResult == E_PENDING) { // The script cache isn't primed with enough info yet. We need to select our HFONT into // a DC and pass the DC in to ScriptPlace. HWndDC hdc(0); HFONT hfont = fontData->platformData().hfont(); HFONT oldFont = (HFONT)SelectObject(hdc, hfont); placeResult = ScriptPlace(hdc, fontData->scriptCache(), glyphs.data(), glyphs.size(), visualAttributes.data(), &item.a, advances.data(), offsets.data(), 0); SelectObject(hdc, oldFont); } if (FAILED(placeResult) || glyphs.isEmpty()) return true; // Convert all chars that should be treated as spaces to use the space glyph. // We also create a map that allows us to quickly go from space glyphs back to their corresponding characters. Vector<int> spaceCharacters(glyphs.size()); spaceCharacters.fill(-1); const float cLogicalScale = fontData->platformData().useGDI() ? 1.0f : 32.0f; float spaceWidth = fontData->spaceWidth() - fontData->syntheticBoldOffset(); unsigned logicalSpaceWidth = spaceWidth * cLogicalScale; for (int k = 0; k < len; k++) { UChar ch = *(str + k); bool treatAsSpace = FontCascade::treatAsSpace(ch); bool treatAsZeroWidthSpace = FontCascade::treatAsZeroWidthSpace(ch); if (treatAsSpace || treatAsZeroWidthSpace) { // Substitute in the space glyph at the appropriate place in the glyphs // array. glyphs[clusters[k]] = fontData->spaceGlyph(); advances[clusters[k]] = treatAsSpace ? logicalSpaceWidth : 0; if (treatAsSpace) spaceCharacters[clusters[k]] = m_currentCharacter + k + item.iCharPos; } } // Populate our glyph buffer with this information. bool hasExtraSpacing = m_font.letterSpacing() || m_font.wordSpacing() || m_padding; float leftEdge = m_runWidthSoFar; for (unsigned k = 0; k < glyphs.size(); k++) { Glyph glyph = glyphs[k]; float advance = advances[k] / cLogicalScale; float offsetX = offsets[k].du / cLogicalScale; float offsetY = offsets[k].dv / cLogicalScale; // Match AppKit's rules for the integer vs. non-integer rendering modes. float roundedAdvance = roundf(advance); if (!fontData->platformData().isSystemFont()) { advance = roundedAdvance; offsetX = roundf(offsetX); offsetY = roundf(offsetY); } advance += fontData->syntheticBoldOffset(); if (hasExtraSpacing) { // If we're a glyph with an advance, go ahead and add in letter-spacing. // That way we weed out zero width lurkers. This behavior matches the fast text code path. if (advance && m_font.letterSpacing()) advance += m_font.letterSpacing(); // Handle justification and word-spacing. int characterIndex = spaceCharacters[k]; // characterIndex is left at the initial value of -1 for glyphs that do not map back to treated-as-space characters. if (characterIndex != -1) { // Account for padding. WebCore uses space padding to justify text. // We distribute the specified padding over the available spaces in the run. if (m_padding) { // Use leftover padding if not evenly divisible by number of spaces. if (m_padding < m_padPerSpace) { advance += m_padding; m_padding = 0; } else { m_padding -= m_padPerSpace; advance += m_padPerSpace; } } // Account for word-spacing. if (characterIndex > 0 && m_font.wordSpacing()) { UChar candidateSpace; if (m_run.is8Bit()) candidateSpace = *(m_run.data8(characterIndex - 1)); else candidateSpace = *(m_run.data16(characterIndex - 1)); if (!FontCascade::treatAsSpace(candidateSpace)) advance += m_font.wordSpacing(); } } } m_runWidthSoFar += advance; // FIXME: We need to take the GOFFSETS for combining glyphs and store them in the glyph buffer // as well, so that when the time comes to draw those glyphs, we can apply the appropriate // translation. if (glyphBuffer) { FloatSize size(offsetX, -offsetY); glyphBuffer->add(glyph, fontData, advance, GlyphBuffer::noOffset, &size); } FloatRect glyphBounds = fontData->boundsForGlyph(glyph); glyphBounds.move(m_glyphOrigin.x(), m_glyphOrigin.y()); m_minGlyphBoundingBoxX = min(m_minGlyphBoundingBoxX, glyphBounds.x()); m_maxGlyphBoundingBoxX = max(m_maxGlyphBoundingBoxX, glyphBounds.maxX()); m_minGlyphBoundingBoxY = min(m_minGlyphBoundingBoxY, glyphBounds.y()); m_maxGlyphBoundingBoxY = max(m_maxGlyphBoundingBoxY, glyphBounds.maxY()); m_glyphOrigin.move(advance + offsetX, -offsetY); // Mutate the glyph array to contain our altered advances. if (m_computingOffsetPosition) advances[k] = advance; } while (m_computingOffsetPosition && m_offsetX >= leftEdge && m_offsetX < m_runWidthSoFar) { // The position is somewhere inside this run. int trailing = 0; HRESULT rc = ::ScriptXtoCP(m_offsetX - leftEdge, clusters.size(), glyphs.size(), clusters.data(), visualAttributes.data(), advances.data(), &item.a, &m_offsetPosition, &trailing); if (FAILED(rc)) { WTFLogAlways("UniscribeController::shapeAndPlaceItem: ScriptXtoCP failed rc=%lx", rc); return true; } if (trailing && m_includePartialGlyphs && m_offsetPosition < len - 1) { m_offsetPosition += m_currentCharacter + m_items[i].iCharPos; m_offsetX += m_run.rtl() ? -trailing : trailing; } else { m_computingOffsetPosition = false; m_offsetPosition += m_currentCharacter + m_items[i].iCharPos; if (trailing && m_includePartialGlyphs) m_offsetPosition++; return false; } } return true; }