wxDC bug in Windows? Desperately need help Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
cecilio
I live to help wx-kind
I live to help wx-kind
Posts: 189
Joined: Fri Dec 03, 2004 8:44 am
Location: spain
Contact:

wxDC bug in Windows? Desperately need help

Post by cecilio »

I had all prepared to release my program. I was doing some final tests by running it in other computers when I found the next bug and I am stucked here since then, three weeks ago.

Look at the folowing display:

Image

Please, note that staff lines and note stems are rendered using DC->DrawLine() and that musical symbols (clef, time signature and note heads are rendered using DC->DrawText(). The problem is the clipping region that exists. Observe that due to the cliping line the first notehead is not rendered., and the clef and time signature are clipped.

This clipping region apears spontaneously for a certain very limited scaling factors . And it apears only for the text. Note that the lines get perfectly rendered, so it is not a problem with the DC clipping region (although I don't use clipping regions) or repaint rectangles computation. The offending scale range varies from computer to computer and even does not exist. In the shown example the trouble zooming factors are between 185% and 215%. For any other zooming factor the program works perfectly.

I've been trying to determine the problem, suspecting from my code (repaint rectangles, destroying clipping region before using the DC, ...) but I can not find anything wrong and the behaviour does not change. So I did the following test:


I modified notehead renderization code adding DC->DrawRectangle() just after rendering the note head. Here is the code (3 added lines commented out):

Code: Select all

    } else {
        // else (drawing phase) do the draw
        wxPoint pos = GetGlyphPosition();
        pDC->SetTextForeground(colorC);
        pDC->DrawText(sGlyph, pos.x, pos.y );
        //lmMicrons nWidth, nHeight;
        //pDC->GetTextExtent(sGlyph, &nWidth, &nHeight);
        //pDC->DrawRectangle(pos.x, pos.y, nWidth, nHeight);
        wxLogMessage(_T("[lmNote::DrawNoteHead] pos=(%d, %d)"), pos.x, pos.y);
    }
The result is in the next picture:

Image


So my conclusion is that the DC is not clipped as the rectangles get perfectly rendered. Also I can not see anything in my code to cause the text being clipped.

I am desperate. I do not know how to continue and I have the program release suspended just because this bug!!!

Could you please help me? Is there is a bug in wxDC (windows XP and WIndows 98 version)? Other ideas? The problem happens with 2.6.2 and with 2.6.3

Thank you very much.[/img]
phlox81
wxWorld Domination!
wxWorld Domination!
Posts: 1387
Joined: Thu Aug 18, 2005 7:49 pm
Location: Germany
Contact:

Post by phlox81 »

Hm, maybe some font issue or anything else in Drawtext.
Have you thought about using images to draw the text and the symbols ?
Does the Problem only occur when you use DrawText ?
Have you tried DrawLabel ?
cecilio
I live to help wx-kind
I live to help wx-kind
Posts: 189
Joined: Fri Dec 03, 2004 8:44 am
Location: spain
Contact:

Post by cecilio »

Thanks phlox81,

Using images is not a good solution as you need good scaling behaviour for high quality printing, zooming, etc. So only two posible soltions: scaling fonts (TrueType, PostScripty, etc) or direct drawing of the glyphs.

The problem is only in DarwText method not in any other one (I only use DrawText, DrawLine, DrawPolygon). I have not tried with DrawLabel; I will do a test using DrawLabel but just for testing as in any case I think it is not the most appropiate method for the intended purpose.

I will tell you.

What kind of problems with the font are you thinking about? (I designed the font so it can be badly designed).

Thank you.
cecilio
I live to help wx-kind
I live to help wx-kind
Posts: 189
Joined: Fri Dec 03, 2004 8:44 am
Location: spain
Contact:

Post by cecilio »

There is no difference using DrawLabel instead of DrawText . The same text clipping takes place.

Used code:

Code: Select all

        // else (drawing phase) do the draw
        wxPoint pos = GetGlyphPosition();
        pDC->SetTextForeground(colorC);
        //pDC->DrawText(sGlyph, pos.x, pos.y );
        lmMicrons nWidth, nHeight;
        pDC->GetTextExtent(sGlyph, &nWidth, &nHeight);
        wxRect rect(pos.x, pos.y, nWidth, nHeight);
        pDC->DrawLabel(sGlyph, rect);
 
goeba
Earned a small fee
Earned a small fee
Posts: 21
Joined: Tue May 17, 2005 8:13 pm

Post by goeba »

Hi,

from the //else in your code I guess that there is other stuff done in that function.

Is this a OnPaint Event handler??

Be aware of the following piece of information:

----------------------cite docs
wxPaintDC
A wxPaintDC must be constructed if an application wishes to paint on the client area of a window from within an OnPaint event. This should normally be constructed as a temporary stack object; don't store a wxPaintDC object. If you have an OnPaint handler, you must create a wxPaintDC object within it even if you don't actually use it.

Using wxPaintDC within OnPaint is important because it automatically sets the clipping area to the damaged area of the window. Attempts to draw outside this area do not appear.

To draw on a window from outside OnPaint, construct a wxClientDC object.

To draw on the whole window including decorations, construct a wxWindowDC object (Windows only).
---------------------end cite

I guess something strange, because your code looks right.

Regards,

Andreas
cecilio
I live to help wx-kind
I live to help wx-kind
Posts: 189
Joined: Fri Dec 03, 2004 8:44 am
Location: spain
Contact:

Post by cecilio »

Hi Andreas,

Thank you for your help. As regards to your points:

The code is not part the an OnPaint event handler. The OnPaint event hnadler is this (full code);

Code: Select all

void lmScoreCanvas::OnPaint(wxPaintEvent &WXUNUSED(event))
{
    // In a paint event handler, the application must always create a wxPaintDC object, 
    // even if it is not used. Otherwise, under MS Windows, refreshing for this and 
    // other windows will go wrong.
    wxPaintDC dc(this);
    if (!m_pView) return;

    // get the updated rectangles list
    wxRegionIterator upd(GetUpdateRegion());    
    
    // iterate to redraw each damaged rectangle
    // The rectangles are in pixels, referred to the client area, and are unscrolled
    while (upd) {
        wxRect rect = upd.GetRect();
        m_pView->RepaintScoreRectangle(&dc, rect);
        upd++;
    }

}
Now, for repainting the damaged rectangles the next method is used (note that I have deleted a lot of lines to leave just the relevant code):

Code: Select all

void lmScoreView::RepaintScoreRectangle(wxDC* pDC, wxRect& repaintRect)
{

    // Note: un-important code lines have been supressed
    
     // inform the score that we are going to use it
    lmScore *pScore = ((lmScoreDocument *)GetDocument())->GetScore();
    if (!pScore) return;
    pScore->PrepareBitmaps(xPageSize, yPageSize, m_rScale);
    
    //note that to prepare the offscreen bitmpas the score object uses a 
    //wxMemoryDC. This DC is the one received by the Draw methods, 
   //such as the excerpt shown in a previous post.
   
    
    // allocate a DC in memory for using the offscreen bitmaps
    wxMemoryDC memoryDC;
    
    // ask for the offscreen bitmap of this page
    wxBitmap* pPageBitmap = pScore->GetOffscreenBitmap(nPag);
    wxASSERT(pPageBitmap && pPageBitmap->Ok());
    memoryDC.SelectObject(*pPageBitmap);


    // Copy the damaged rectangle onto the device DC
    pDC->Blit(xCanvas, yCanvas, interRect.width, interRect.height,
                &memoryDC, xBitmap, yBitmap);

}
As you can see, I use an wxPainDC and draw on it with a Blit operation from a bitmap.
For preparing the bitmap I use a wxMemoryDC (not shown in the code. This memoryDC is allocated as part of the Score::PrepareBitmaps() method. The bitmaps are not always re-created, only when needed)

As I copy from a memoryDC to the paintDC it is very shocking to me that the text get clipped and no other elements such as lines or rectangles. So my conclusion is that the clipping takes place when preparing the bitmaps

So, my questions are:

1. how a DrawText operation onto a memoryDC can be clipped appart of by using clipping rectangles?

2. Could you suggest me things to do to try to isolate the problem?


Thank you very much
goeba
Earned a small fee
Earned a small fee
Posts: 21
Joined: Tue May 17, 2005 8:13 pm

Post by goeba »

Hi,

I have the following ideas:

- Memory-DC
toxicBunny
Super wx Problem Solver
Super wx Problem Solver
Posts: 424
Joined: Tue Jul 12, 2005 8:44 pm
Location: Alabama, USA

Post by toxicBunny »

You could try saving the bitmap used by the memory dc to see if the problem happens in the drawing or during the blit operation.

Additionally, I believe that all of the wxWidgets drawing routines take integers as drawing coordinates. Depending on the scaling/magnification factors, it may be possible that some sort of rounding or truncation is being done on the coordinates causing the clipping area to be too small.

Of course, these are just guesses at this point...

-Scott
wxMSW 2.6.2, VS 2002, 2003 and 2005, Code::Blocks and mingw, Windows XP Pro
cecilio
I live to help wx-kind
I live to help wx-kind
Posts: 189
Joined: Fri Dec 03, 2004 8:44 am
Location: spain
Contact:

Post by cecilio »

Hi Andreas and Scott,

Thank you very much for your suggestions.

I've been trying to find the problem but without success. Doing tests takes me some time because the problem does not happen in the machine I use for development and I have to move to another building far away to do the tests. So it is quite tedious to prepare a test, move to the other place, install the code in the test machine and do the test. So I can only do one or two tests per day.

Now the situation is as follows:

1. I saved the bitmap used by the memory dc to see if the problem happens in the drawing or during the blit operation. The conclusion is that the error happens during the drawing.

2. As Scott suggested, I was also suspecting about truncation errors. My logical units are microns (one thousand of millimeter), so I use MM_LOMETRIC and a user scale of 0.01. The user space is a sheet of paper. Assuming as maximum a DIN A2 paper (42.0 x 59.4 cm) the coordinate values will go from 0 to 420,000 x 594,000 in thousandths of a mm (one micron). As thw wxDC uses variables of type int32 (-2,146,483,648 to +2,147,483,647) I think that there are no problems (although perhaps during computations, when multiplying two coordinates, overflows could occur). Also, due to the high resolution, the font size used by the DrawText() was of 5400pt, so I also suspected about using such a big font size.

So I changed the program to be able to use different logical units. Now I moved to thents of millimiters (MM_LOMETRIC and a user scale of 1.00. Font size now is 54pt With this new values the results are:

- In Windows 2000 the problem continues, again for magnification factors ranging from about 185% to 215% (this implies MM_LOMETRIC and a user scale of 0.01*1,85 or 0.01*2.15)
- In Windows 98 the problem seems fixed, although I didn't try with many zooming factors.
- In Windows XP, as before, no problem detected.


So I still supect from wxMemoryDC->DrawText() involved code.


Anyway, this is takimg me too much time so I will forget about this problem and continue with my working plans.

Thank you very much for your time.

King regards.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7477
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Post by ONEEYEMAN »

Cecilio and guys,
Did you check the MS knoweledge base? Maybe there is a bug in the Windows 98/2K itself, with the LO_METRIC, that prevents this code to work fine?
It's even possible there is a workaround for it...

Thank you.
Post Reply