diff --git a/src/servers/app/server/AccelerantDriver.cpp b/src/servers/app/server/AccelerantDriver.cpp index b1aca209e9..58ecac8259 100644 --- a/src/servers/app/server/AccelerantDriver.cpp +++ b/src/servers/app/server/AccelerantDriver.cpp @@ -26,6 +26,8 @@ // //------------------------------------------------------------------------------ #include "AccelerantDriver.h" +#include "Angle.h" +#include "FontFamily.h" #include "ServerCursor.h" #include "ServerBitmap.h" #include "LayerData.h" @@ -36,13 +38,53 @@ #define RUN_UNDER_R5 +#define CLIP_X(a) ( (a < 0) ? 0 : ((a > mDisplayMode.virtual_width-1) ? \ + mDisplayMode.virtual_width-1 : a) ) +#define CLIP_Y(a) ( (a < 0) ? 0 : ((a > mDisplayMode.virtual_height-1) ? \ + mDisplayMode.virtual_height-1 : a) ) +#define CHECK_X(a) ( (a >= 0) || (a <= mDisplayMode.virtual_width-1) ) +#define CHECK_Y(a) ( (a >= 0) || (a <= mDisplayMode.virtual_height-1) ) + /* Stuff to investigate: Effect of pensize on fill operations Pattern details - start point, rectangles drawn counter-clockwise? Maybe the pattern is always relative to (0,0) + Do I need to deal with things that may be clipped entirely? */ /* Need to check which functions should move the pen position */ +class AccLineCalc +{ +public: + AccLineCalc(const BPoint &pta, const BPoint &ptb); + float GetX(float y); + float GetY(float x); + float Slope(void) { return slope; } + float Offset(void) { return offset; } +private: + float slope; + float offset; + BPoint start, end; +}; + +AccLineCalc::AccLineCalc(const BPoint &pta, const BPoint &ptb) +{ + start=pta; + end=ptb; + slope=(start.y-end.y)/(start.x-end.x); + offset=start.y-(slope * start.x); +} + +float AccLineCalc::GetX(float y) +{ + return ( (y-offset)/slope ); +} + +float AccLineCalc::GetY(float x) +{ + return ( (slope * x) + offset ); +} + /*! \brief Sets up internal variables needed by AccelerantDriver @@ -236,6 +278,150 @@ void AccelerantDriver::DrawBitmap(ServerBitmap *bmp, BRect src, BRect dest, Laye */ void AccelerantDriver::DrawString(const char *string, int32 length, BPoint pt, LayerData *d, escapement_delta *delta=NULL) { +#if 0 + if(!string || !d || !d->font) + return; + + _Lock(); + + pt.y--; // because of Be's backward compatibility hack + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return; + } + + FT_Face face; + FT_GlyphSlot slot; + FT_Matrix rmatrix,smatrix; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta,space,nonspace; + int16 error=0; + int32 strlength,i; + Angle rotation(font->Rotation()), shear(font->Shear()); + + bool antialias=( (font->Size()<18 && font->Flags()& B_DISABLE_ANTIALIASING==0) + || font->Flags()& B_FORCE_ANTIALIASING)?true:false; + + // Originally, I thought to do this shear checking here, but it really should be + // done in BFont::SetShear() + float shearangle=shear.Value(); + if(shearangle>135) + shearangle=135; + if(shearangle<45) + shearangle=45; + + if(shearangle>90) + shear=90+((180-shearangle)*2); + else + shear=90-(90-shearangle)*2; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + printf("Couldn't create face object\n"); + _Unlock(); + return; + } + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return; + } + + // if we do any transformation, we do a call to FT_Set_Transform() here + + // First, rotate + rmatrix.xx = (FT_Fixed)( rotation.Cosine()*0x10000); + rmatrix.xy = (FT_Fixed)( rotation.Sine()*0x10000); + rmatrix.yx = (FT_Fixed)(-rotation.Sine()*0x10000); + rmatrix.yy = (FT_Fixed)( rotation.Cosine()*0x10000); + + // Next, shear + smatrix.xx = (FT_Fixed)(0x10000); + smatrix.xy = (FT_Fixed)(-shear.Cosine()*0x10000); + smatrix.yx = (FT_Fixed)(0); + smatrix.yy = (FT_Fixed)(0x10000); + + //FT_Matrix_Multiply(&rmatrix,&smatrix); + FT_Matrix_Multiply(&smatrix,&rmatrix); + + // Set up the increment value for escapement padding + space.x=int32(d->edelta.space * rotation.Cosine()*64); + space.y=int32(d->edelta.space * rotation.Sine()*64); + nonspace.x=int32(d->edelta.nonspace * rotation.Cosine()*64); + nonspace.y=int32(d->edelta.nonspace * rotation.Sine()*64); + + // set the pen position in 26.6 cartesian space coordinates + pen.x=(int32)pt.x * 64; + pen.y=(int32)pt.y * 64; + + slot=face->glyph; + + + strlength=strlen(string); + if(lengthbitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + else + BlitMono2RGB32(&slot->bitmap, + BPoint(slot->bitmap_left,pt.y-(slot->bitmap_top-pt.y)), d); + } + else + printf("Couldn't load character %c\n", string[i]); + + // increment pen position + pen.x+=slot->advance.x; + pen.y+=slot->advance.y; + previous=glyph_index; + } + FT_Done_Face(face); + _Unlock(); +#endif } /*! @@ -251,6 +437,169 @@ void AccelerantDriver::DrawString(const char *string, int32 length, BPoint pt, L */ void AccelerantDriver::FillArc(BRect r, float angle, float span, LayerData *d, int8 *pat) { + /* Need to add bounds checking code */ + float xc = (r.left+r.right)/2; + float yc = (r.top+r.bottom)/2; + float rx = r.Width()/2; + float ry = r.Height()/2; + int Rx2 = ROUND(rx*rx); + int Ry2 = ROUND(ry*ry); + int twoRx2 = 2*Rx2; + int twoRy2 = 2*Ry2; + int p; + int x=0; + int y = (int)ry; + int px = 0; + int py = twoRx2 * y; + int startx, endx; + int startQuad, endQuad; + bool useQuad1, useQuad2, useQuad3, useQuad4; + bool shortspan = false; + int thick; + + // Watch out for bozos giving us whacko spans + if ( (span >= 360) || (span <= -360) ) + { + StrokeEllipse(r,d,pat); + return; + } + + _Lock(); + thick = (int)d->pensize; + if ( span > 0 ) + { + startQuad = (int)(angle/90)%4+1; + endQuad = (int)((angle+span)/90)%4+1; + startx = ROUND(.5*r.Width()*fabs(cos(angle*M_PI/180))); + endx = ROUND(.5*r.Width()*fabs(cos((angle+span)*M_PI/180))); + } + else + { + endQuad = (int)(angle/90)%4+1; + startQuad = (int)((angle+span)/90)%4+1; + endx = ROUND(.5*r.Width()*fabs(cos(angle*M_PI/180))); + startx = ROUND(.5*r.Width()*fabs(cos((angle+span)*M_PI/180))); + } + + if ( startQuad != endQuad ) + { + useQuad1 = (endQuad > 1) && (startQuad > endQuad); + useQuad2 = ((startQuad == 1) && (endQuad > 2)) || ((startQuad > endQuad) && (endQuad > 2)); + useQuad3 = ((startQuad < 3) && (endQuad == 4)) || ((startQuad < 3) && (endQuad < startQuad)); + useQuad4 = (startQuad < 4) && (startQuad > endQuad); + } + else + { + if ( (span < 90) && (span > -90) ) + { + useQuad1 = false; + useQuad2 = false; + useQuad3 = false; + useQuad4 = false; + shortspan = true; + } + else + { + useQuad1 = (startQuad != 1); + useQuad2 = (startQuad != 2); + useQuad3 = (startQuad != 3); + useQuad4 = (startQuad != 4); + } + } + + /* + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + */ + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) ) + { + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) ) + { + HLine(xc-x, xc+x, yc-y, d, pat); + } + } + + p = ROUND (Ry2 - (Rx2 * ry) + (.25 * Rx2)); + while (px < py) + { + x++; + px += twoRy2; + if ( p < 0 ) + p += Ry2 + px; + else + { + y--; + py -= twoRx2; + p += Ry2 + px - py; + } + + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + } + + p = ROUND(Ry2*(x+.5)*(x+.5) + Rx2*(y-1)*(y-1) - Rx2*Ry2); + while (y>0) + { + y--; + py -= twoRx2; + if (p>0) + p += Rx2 - py; + else + { + x++; + px += twoRy2; + p += Rx2 - py +px; + } + + if ( useQuad1 || + (!shortspan && (((startQuad == 1) && (x <= startx)) || ((endQuad == 1) && (x >= endx)))) || + (shortspan && (startQuad == 1) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc+x,yc-y,thick,d->highcolor); + if ( useQuad2 || + (!shortspan && (((startQuad == 2) && (x >= startx)) || ((endQuad == 2) && (x <= endx)))) || + (shortspan && (startQuad == 2) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc-x,yc-y,thick,d->highcolor); + if ( useQuad3 || + (!shortspan && (((startQuad == 3) && (x <= startx)) || ((endQuad == 3) && (x >= endx)))) || + (shortspan && (startQuad == 3) && (x <= startx) && (x >= endx)) ) + SetThickPixel(xc-x,yc+y,thick,d->highcolor); + if ( useQuad4 || + (!shortspan && (((startQuad == 4) && (x >= startx)) || ((endQuad == 4) && (x <= endx)))) || + (shortspan && (startQuad == 4) && (x >= startx) && (x <= endx)) ) + SetThickPixel(xc+x,yc+y,thick,d->highcolor); + } + _Unlock(); + } /*! @@ -349,14 +698,26 @@ void AccelerantDriver::FillEllipse(BRect r, LayerData *d, int8 *pat) _Lock(); + if ( (r.bottom < 0) || (r.top > mDisplayMode.virtual_height-1) || + (r.right < 0) || (r.left > mDisplayMode.virtual_width-1) ) + { + _Unlock(); + return; + } + /* SetThickPixel(xc+x,yc-y,thick,d->highcolor); SetThickPixel(xc-x,yc-y,thick,d->highcolor); SetThickPixel(xc-x,yc+y,thick,d->highcolor); SetThickPixel(xc+x,yc+y,thick,d->highcolor); */ - SetPixel(xc,yc-y,d->highcolor); - SetPixel(xc,yc+y,d->highcolor); + if ( CHECK_X(xc) ) + { + if ( CHECK_Y(yc-y) ) + SetPixel(xc,yc-y,d->highcolor); + if ( CHECK_Y(yc+y) ) + SetPixel(xc,yc+y,d->highcolor); + } p = ROUND (Ry2 - (Rx2 * ry) + (.25 * Rx2)); while (px < py) @@ -378,8 +739,13 @@ void AccelerantDriver::FillEllipse(BRect r, LayerData *d, int8 *pat) SetThickPixel(xc-x,yc+y,thick,d->highcolor); SetThickPixel(xc+x,yc+y,thick,d->highcolor); */ - HLine(xc-x,xc+x,yc-y,d->highcolor); - HLine(xc-x,xc+x,yc+y,d->highcolor); + if ( CHECK_X(xc-x) || CHECK_X(xc+x) ) + { + if ( CHECK_Y(yc-y) ) + HLine(CLIP_X(xc-x),CLIP_X(xc+x),yc-y,d,pat); + if ( CHECK_Y(yc+y) ) + HLine(CLIP_X(xc-x),CLIP_X(xc+x),yc+y,d,pat); + } } p = ROUND(Ry2*(x+.5)*(x+.5) + Rx2*(y-1)*(y-1) - Rx2*Ry2); @@ -402,8 +768,13 @@ void AccelerantDriver::FillEllipse(BRect r, LayerData *d, int8 *pat) SetThickPixel(xc-x,yc+y,thick,d->highcolor); SetThickPixel(xc+x,yc+y,thick,d->highcolor); */ - HLine(xc-x,xc+x,yc-y,d->highcolor); - HLine(xc-x,xc+x,yc+y,d->highcolor); + if ( CHECK_X(xc-x) || CHECK_X(xc+x) ) + { + if ( CHECK_Y(yc-y) ) + HLine(CLIP_X(xc-x),CLIP_X(xc+x),yc-y,d,pat); + if ( CHECK_Y(yc+y) ) + HLine(CLIP_X(xc-x),CLIP_X(xc+x),yc+y,d,pat); + } } _Unlock(); } @@ -421,6 +792,10 @@ void AccelerantDriver::FillEllipse(BRect r, LayerData *d, int8 *pat) */ void AccelerantDriver::FillPolygon(BPoint *ptlist, int32 numpts, BRect rect, LayerData *d, int8 *pat) { + /* The current plan is to transform the polygon into trianles and rectangles, and + use the apporiate commands to draw each part. Maybe I'll come up with something + better later. + */ } /*! @@ -439,7 +814,22 @@ void AccelerantDriver::FillRect(BRect r, LayerData *d, int8 *pat) switch (mDisplayMode.space) { case B_CMAP8: + case B_GRAY8: { + uint8 *fb = (uint8 *)mFrameBufferConfig.frame_buffer + (int)r.top*mFrameBufferConfig.bytes_per_row; + int x,y; + uint8 drawcolor = d->highcolor.GetColor8(); + for (y=(int)r.top; y<=(int)r.bottom; y++) + { + /* If there is no pattern, we could replace this + loop with a memset. + */ + for (x=(int)r.left; x<=r.right; x++) + { + fb[x] = drawcolor; + } + fb += mFrameBufferConfig.bytes_per_row; + } } break; case B_RGB16_BIG: case B_RGB16_LITTLE: @@ -448,6 +838,17 @@ void AccelerantDriver::FillRect(BRect r, LayerData *d, int8 *pat) case B_RGB15_LITTLE: case B_RGBA15_LITTLE: { + uint16 *fb = (uint16 *)((uint8 *)mFrameBufferConfig.frame_buffer + (int)r.top*mFrameBufferConfig.bytes_per_row); + int x,y; + uint16 drawcolor = d->highcolor.GetColor16(); + for (y=(int)r.top; y<=(int)r.bottom; y++) + { + for (x=(int)r.left; x<=r.right; x++) + { + fb[x] = drawcolor; + } + fb = (uint16 *)((uint8 *)fb + mFrameBufferConfig.bytes_per_row); + } } break; case B_RGB32_BIG: case B_RGBA32_BIG: @@ -492,16 +893,26 @@ void AccelerantDriver::FillRoundRect(BRect r, float xrad, float yrad, LayerData int i; _Lock(); + + if ( (r.bottom < 0) || (r.top > mDisplayMode.virtual_height-1) || + (r.right < 0) || (r.left > mDisplayMode.virtual_width-1) ) + { + _Unlock(); + return; + } for (i=0; ifont) + return 0.0; + _Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return 0.0; + } + + FT_Face face; + FT_GlyphSlot slot; + FT_UInt glyph_index, previous=0; + FT_Vector pen,delta; + int16 error=0; + int32 strlength,i; + float returnval; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + bool use_kerning=FT_HAS_KERNING(face) && font->Spacing()==B_STRING_SPACING; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return 0.0; + } + + // set the pen position in 26.6 cartesian space coordinates + pen.x=0; + + slot=face->glyph; + + strlength=strlen(string); + if(lengthadvance.x; + previous=glyph_index; + } + + FT_Done_Face(face); + + returnval=pen.x>>6; + _Unlock(); + return returnval; } /*! @@ -1259,7 +1842,62 @@ float AccelerantDriver::StringWidth(const char *string, int32 length, LayerData */ float AccelerantDriver::StringHeight(const char *string, int32 length, LayerData *d) { - return 0.0; + if(!string || !d || !d->font) + return 0.0; + _Lock(); + + ServerFont *font=d->font; + FontStyle *style=font->Style(); + + if(!style) + { + _Unlock(); + return 0.0; + } + + FT_Face face; + FT_GlyphSlot slot; + int16 error=0; + int32 strlength,i; + float returnval=0.0,ascent=0.0,descent=0.0; + + error=FT_New_Face(ftlib, style->GetPath(), 0, &face); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + error=FT_Set_Char_Size(face, 0,int32(font->Size())*64,72,72); + if(error) + { + _Unlock(); + return 0.0; + } + + slot=face->glyph; + + strlength=strlen(string); + if(lengthmetrics.horiBearingYmetrics.height) + descent=MAX((slot->metrics.height-slot->metrics.horiBearingY)>>6,descent); + else + ascent=MAX(slot->bitmap.rows,ascent); + } + _Unlock(); + + FT_Done_Face(face); + + returnval=ascent+descent; + _Unlock(); + return returnval; } /*! @@ -1342,7 +1980,10 @@ void AccelerantDriver::SetPixel(int x, int y, RGBColor col) switch (mDisplayMode.space) { case B_CMAP8: + case B_GRAY8: { + uint8 *fb = (uint8 *)mFrameBufferConfig.frame_buffer + y*mFrameBufferConfig.bytes_per_row; + fb[x] = col.GetColor8(); } break; case B_RGB16_BIG: case B_RGB16_LITTLE: @@ -1351,6 +1992,8 @@ void AccelerantDriver::SetPixel(int x, int y, RGBColor col) case B_RGB15_LITTLE: case B_RGBA15_LITTLE: { + uint16 *fb = (uint16 *)((uint8 *)mFrameBufferConfig.frame_buffer + y*mFrameBufferConfig.bytes_per_row); + fb[x] = col.GetColor16(); } break; case B_RGB32_BIG: case B_RGBA32_BIG: @@ -1372,7 +2015,22 @@ void AccelerantDriver::SetThickPixel(int x, int y, int thick, RGBColor col) switch (mDisplayMode.space) { case B_CMAP8: + case B_GRAY8: { + int i,j; + uint8 *fb = (uint8 *)mFrameBufferConfig.frame_buffer + (y-thick/2)*mFrameBufferConfig.bytes_per_row + x-thick/2; + uint8 drawcolor = col.GetColor8(); + for (i=0; ihighcolor.GetColor32(); uint32 drawcolor = (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue); int x; if ( x1 > x2 ) @@ -1450,10 +2119,8 @@ void AccelerantDriver::BlitBitmap(ServerBitmap *sourcebmp, BRect sourcerect, BRe if(!sourcebmp) return; - /* Need to fix this - if(sourcebmp->BitsPerPixel() != fbuffer->gcinfo.bits_per_pixel) + if(sourcebmp->BitsPerPixel() != GetDepthFromColorspace(mDisplayMode.space)) return; - */ uint8 colorspace_size=sourcebmp->BitsPerPixel()/8; // First, clip source rect to destination @@ -1574,10 +2241,8 @@ void AccelerantDriver::ExtractToBitmap(ServerBitmap *destbmp, BRect destrect, BR if(!destbmp) return; - /* Need to fix this - if(destbmp->BitsPerPixel() != fbuffer->gcinfo.bits_per_pixel) + if(destbmp->BitsPerPixel() != GetDepthFromColorspace(mDisplayMode.space)) return; - */ uint8 colorspace_size=destbmp->BitsPerPixel()/8; // First, clip source rect to destination @@ -1662,11 +2327,7 @@ int AccelerantDriver::OpenGraphicsDevice(int deviceNumber) char path[PATH_MAX]; DIR *directory; struct dirent *entry; -#if 0 - //card_fd = open("/dev/graphics/1002_4755_000400",B_READ_WRITE); - card_fd = open("/dev/graphics/nv10_010000",B_READ_WRITE); - //card_fd = open("/dev/graphics/stub",B_READ_WRITE); -#endif + directory = opendir("/dev/graphics"); if ( !directory ) return -1; diff --git a/src/servers/app/server/AccelerantDriver.h b/src/servers/app/server/AccelerantDriver.h index 982e41a405..95754437b0 100644 --- a/src/servers/app/server/AccelerantDriver.h +++ b/src/servers/app/server/AccelerantDriver.h @@ -115,7 +115,7 @@ protected: void ExtractToBitmap(ServerBitmap *destbmp, BRect destrect, BRect sourcerect); void SetPixelPattern(int x, int y, uint8 *pattern, uint8 patternindex); void Line(BPoint start, BPoint end, LayerData *d, int8 *pat); - void HLine(int32 x1, int32 x2, int32 y, RGBColor col); + void HLine(int32 x1, int32 x2, int32 y, LayerData *d, int8 *pat); rgb_color GetBlitColor(rgb_color src, rgb_color dest, LayerData *d, bool use_high=true); void SetPixel(int x, int y, RGBColor col); void SetPixel32(int x, int y, rgb_color col);