Greg Ercolano wrote: > Albrecht Schlosser wrote: >> Yes, really interesting, nice demo. > > Yes, it appears that fl_rect() was not piling on the extra pixel > thickness in a 'predictable' way; the extra pixel was ending up > on the /inside/ of the rectangle for the right and bottom edges only; > for the other two edges the extra pixel ended up /outside/ the > rectangle, causing those to get clipped, making a lopsided rectangle. > > I'm imagining fl_rect() is implemented as four fl_line() calls, > so I'm thinking fl_rect() gets to define the direction the lines > are drawn.
It's implemented with whatever drawing primitives the OS provides (src/fl_rect.cxx), and there it happens to become different: USE_X11: XDrawRectangle() WIN32: MoveToEx() + 4x LineTo() APPLE_QUARTZ: CGContextStrokeRect() Interesting point: For Quartz antialiasing is switched off explicitly, if (and only if) the current line width is 1.0f (I'm guessing this from reading the code, but it seems to be obvious). [BTW.: And it is unconditionally set to true afterwards, which might be another bug, if it was false before.] AFAICS the real behavior depends on the drawing properties (like fl_line_style) that have been set previously, because an existing graphics context (fl_gc) is used in all cases, whatever the fl_gc may be in the OS-specific context. > Am I right in thinking that the line directions determine which > side of the line the 'extra pixel' falls on for the line style? This might be OS-dependent, see above. > For odd line thickness, the integer math comes out nicely; > a line thickness of 3 means an extra pixel will appear on > either side of the line. > > But a line thickness of two means a choice has to be made > by the line algorithm to place the extra pixel on either > one side of the line or the other. > > I'd assume if fl_rect()'s four lines are drawn with this > in mind, such that when drawn inside a clipping region, > you'd get a 'consistent' line thickness clipped off around > all edges. Then it would be necessary to adjust the code to the OS-specific behavior of the currently used drawing primitives (might be difficult, and maybe even undefined in some cases?) or always use more basic stuff like calling only single line drawing functions (might be a performance and/or accuracy problem). > But it appears that's not the case with the current behavior, > which should either be documented, or if it's controllable, > made more consistent. > > Documentation for fl_rect() should maybe be added, along the > lines of what FLTK can guarantee, eg: > > fl_line_style's whose line thickness is >0, the line > thickness will grow around the pixel centers of the > defined rectangle. > > For cases of line thickness where the value is even, > the integer math [WILL or WILL NOT?] guarantee the > extra pixels will always fall [INSIDE? OUTSIDE?] > the rectangle's perimeter. > > It seems we should say something, otherwise folks are left > to come up with whatever they think the behavior should be, > and will be surprised when it's not. Yes, it should be documented better. >>> Theoretically, both should look the same (though I guess it depends >>> which side of the dimensions the extra pixel thickness should go for >>> a two pixel thick line), but on all platforms you can see there's >>> flashing going on. >> No, they shouldn't, because... >> >> According to the docs, fl_rect() "Draws a 1-pixel border inside the >> given bounding box." Emphasis on "1-pixel" and "inside". > > Since there's no docs to the contrary, yes, I imagine the > implication is fl_line_style() should grow the extra pixels > inward from the xywh perimeter to follow that rule. Which extra pixel? It's a "1-pixel border" ;-) > To do that though, I imagine fl_rect() would have to check > to see if the line thickness is something other than the default, > and adjust the lines if so to draw inward. That might be tricky > though, if integer math makes this unpredictable. Agreed - IF more than 1 pixel would be allowed/defined at all (see below). > Or, maybe we should just add a comment to the docs saying: > > fl_line_style()s other than the default of zero > may cause the line's edges to fall outside the xywh area. Something like this... >> As I read this, Jane's original code is wrong, and the correct fix is to >> draw two fl_rect()'s, as she did already :-) . > > Right; in my first reply I suspected fl_line_style() was the problem, > and recommended to instead leave its value alone, and just draw > two fl_rects. > > In my second reply, I focused more on the problem of the odd > line style behavior where the line thickness was different for > the top and left edges only. > >> Although it is documented "If you change this it is your responsibility >> to set it back to the default using fl_line_style(0)", it is not >> completely clear (for me) if this means that you must _reset_ the line >> style before calling fl_rect(). If this is true, then everything else is >> undefined behavior, and FLTK is right. ;-) > > Mmm, I only read that one way: "when you change the line style > for your drawing, don't forget to set it back to 0, or it will > remain in effect, affecting other fltk widgets outside your > draw() function." ... or "affecting other drawing functions than simple line drawing". > In other words, FLTK will not reset the line style to zero > whenever your draw() function completes; you have to reset it. IMHO that's the _minimum_ how to interpret it. > Since the above comment is from fl_line_style()'s docs > (and not fl_rect()'s), I don't think there'd be any other > way to read it.. maybe I'm missing something. It's at least a little bit ambiguous, and maybe surprising. > I think it's safe to assume fl_line_style() affects all line > drawing functions, including convenience functions like fl_rect() > (which probably just draws four fl_line()s internally) In general I agree, but the problem with fl_rect() is that it is explicitly defined to draw a _1-pixel_ border (not only in the docs, but also in a comment in the code). However, this is not enforced in the code - it relies on the current setting of the graphics context (fl_gc). I don't know if this is for performance reasons (modifying the graphics context every time might be expensive) or a simple omission. We certainly need comments of the previous authors about what was intended with this code and why. Solution #1 (the documentation is correct, the code is wrong): Save the line properties in static variables (like fl_quartz_line_width_ for Quartz) and change them in the graphics context only if they differ (because this would be an "expensive" function call) and reset them after the drawing function. Solution #2 (the code is correct, the documentation is wrong): Correct the docs to say that fl_rect()'s line width depends on fl_line_style() and try to document the behavior exactly (as far as possible), and maybe also adjust the drawing to draw the additional pixels always _inside_ the fl_rect() as documented. Solution #3... A mix of both? Albrecht _______________________________________________ fltk mailing list [email protected] http://lists.easysw.com/mailman/listinfo/fltk

