extras/html: (~#997) Many fixes and improvements to HTML parser and renderer
authorJerome St-Louis <jerome@ecere.com>
Mon, 30 Sep 2013 07:40:50 +0000 (03:40 -0400)
committerJerome St-Louis <jerome@ecere.com>
Mon, 30 Sep 2013 08:06:43 +0000 (04:06 -0400)
extras/html/HTMLView.ec
extras/html/htmlParser.ec
extras/html/lines.ec
extras/html/tables.ec

index 637afa5..5571895 100644 (file)
@@ -4,6 +4,7 @@ import "htmlParser"
 
 enum BlockType
 {
+   HTML,
    TEXT = 1,
    IMAGE,
    BR,
@@ -15,7 +16,9 @@ enum BlockType
    TD,
    ANCHOR,
    INPUT,
-   FORM
+   FORM,
+   TITLE,
+   HEAD
 };
 
 define LEFT_MARGIN = 10;
@@ -31,7 +34,7 @@ define CELL_SPACING = 0;
 
 class RenderFlags { bool lineW:1,width:1,render:1,minW:1; };
 
-enum InputType { text, submit, radio, hidden };
+enum InputType { text, submit, checkbox, radio, hidden };
 
 class ImageEntry : struct
 {
@@ -125,6 +128,7 @@ class ObjectThread : Thread
                {
                   HTTPFile httpFile {};
                   file = httpFile;
+                  incref file;
                   //printf("Opening URL\n");
 
                   //((GuiApplication)__thisModule).PauseNetworkEvents();
@@ -150,6 +154,7 @@ class ObjectThread : Thread
                      char extension[MAX_EXTENSION];
                      entry.bitmap = Bitmap { alphaBlend = true };
                      entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
+                     incref file;
                   }
                }
                delete file;
@@ -189,8 +194,9 @@ class ObjectThread : Thread
                      browserWindow.Update(null);
 
                      // ((GuiApplication)__thisModule).UpdateDisplay();
+                     display.Unlock();
                   }
-                  display.Unlock();
+
                   // TRIED MOVING THIS HERE BECAUSE OF printf("bug") in GuiApplication if(window.display.current)
                   ((GuiApplication)__thisModule).UpdateDisplay();
                }
@@ -290,10 +296,54 @@ static void ComputeImageSize(Block block)
       ComputeImageSize(child);
 }
 
+// Resources Cache
+Window sharedWindow
+{
+   visible = false;
+
+   bool OnLoadGraphics()
+   {
+      ImageEntry entry;
+      FontEntry fEntry;
+      for(entry = imageCache.first; entry; entry = entry.next)
+      {
+         entry.bitmap.MakeDD(displaySystem);
+         if(entry.bitmap && entry.bitmap.alphaBlend)
+         {
+            entry.bitmap.Convert(null, pixelFormat888, null);
+            // entry.bitmap.displaySystem = displaySystem;
+         }
+      }
+      for(fEntry = fontCache.first; fEntry; fEntry = fEntry.next)
+      {
+         if(!fEntry.font)
+            fEntry.font = displaySystem.LoadFont(fEntry.face, fEntry.size, fEntry.attribs);
+      }
+      return true;
+   }
+   
+   void OnUnloadGraphics()
+   {
+      ImageEntry entry;
+      FontEntry fontEntry;
+      while((entry = imageCache.first))
+      {
+         imageCache.Remove(entry);
+         delete entry;
+      }
+      while((fontEntry = fontCache.first))
+      {
+         displaySystem.UnloadFont(fontEntry.font);
+         fontCache.Remove(fontEntry);
+         delete fontEntry;
+      }
+   }
+};
+
 class HTMLView : Window
 {
    HTMLFile html {};
-   BitmapResource missing { "<:ecere>emblems/unreadable.png", window = this };
+   BitmapResource missing { "<:ecere>emblems/unreadable.png", window = sharedWindow /*this*/ };
    char * location;
    Block overLink, clickedLink;
    Block overBlock;
@@ -423,11 +473,24 @@ class HTMLView : Window
          {
             case submit:
                block.window = Button { this, text = block.value, position = Point { 10, 50 }, id = (int64)block, NotifyClicked = ButtonClicked, isDefault = true };
+               if(block.size)
+                  block.window.size = { w = (int)(block.size * 8) };
+               if(block.src)
+               {
+                  ((Button)block.window).bitmap = { block.src };
+                  ((Button)block.window).bevel = false;
+               }
                eInstance_IncRef(block.window);
                block.window.Create();
                block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
                //if(!html.defaultButton) html.defaultButton = block.window;
                break;
+            case checkbox:
+               block.window = Button { this, isCheckbox = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
+               eInstance_IncRef(block.window);
+               block.window.Create();
+               block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
+               break;
             case radio:
                block.window = Button { this, isRadio = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
                eInstance_IncRef(block.window);
@@ -435,7 +498,11 @@ class HTMLView : Window
                block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
                break;
             case text:
-               block.window = EditBox { this, position = Point { 10, 20 }, id = (int64)block };
+               block.window = EditBox { this, contents = block.value, size = { w = (int)(block.size * 8) }, position = Point { 10, 20 }, id = (int64)block };
+               if(!block.size)
+               {
+                  ((EditBox)block.window).size.w = block.parent.width;
+               }
                eInstance_IncRef(block.window);
                block.window.Create();
                break;
@@ -455,7 +522,7 @@ class HTMLView : Window
       if(block.src && (block.type == IMAGE || block.type == TD || block.type == TABLE))
       {
          char path[MAX_LOCATION];
-         ImageEntry entry;
+         ImageEntry entry = null;
 
          strcpy(path, location ? location : "");
          if(location && path[strlen(path)-1] != '/')
@@ -468,9 +535,12 @@ class HTMLView : Window
          else
             PathCat(path, block.src);
 
-         for(entry = imageCache.first; entry; entry = entry.next)
-            if(!strcmp(entry.src, path))
-               break;
+         if(!strstr(path, "File://"))
+         {
+            for(entry = imageCache.first; entry; entry = entry.next)
+               if(!strcmp(entry.src, path))
+                  break;
+         }
 
          if(!entry)
          {
@@ -524,6 +594,9 @@ class HTMLView : Window
                   char extension[MAX_EXTENSION];
                   entry.bitmap = Bitmap { alphaBlend = true };
                   entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
+                  display.Lock(false);
+                  entry.bitmap.MakeDD(displaySystem);
+                  display.Unlock();
                }
                delete file;
                for(bitmapPtr = entry.bitmapPtrs.first; bitmapPtr; bitmapPtr = bitmapPtr.next)
@@ -534,6 +607,7 @@ class HTMLView : Window
             }
          }
          block.font = block.parent.font;
+         block.textColor = block.parent.textColor;
       }
       else if(block.type == FONT || block.type == ANCHOR)
       {
@@ -550,50 +624,26 @@ class HTMLView : Window
          if(!entry)
          {
             display.Lock(false);
-            entry = FontEntry { /*font = displaySystem.LoadFont(block.face, block.size, block.attribs), */size = block.size, attribs = block.attribs, face = CopyString(block.face) };
+            entry = FontEntry { font = displaySystem.LoadFont(block.face, block.size, block.attribs), size = block.size, attribs = block.attribs, face = CopyString(block.face) };
             fontCache.Add(entry);
             display.Unlock();
          }
 
          if(entry)
-         {
-            // ?
             block.font = entry;
-         }
       }
       else if(block.parent)
-         block.font = block.parent.font;
-
-      for(child = block.subBlocks.first; child; child = child.next)
-         LoadGraphics(child, previous);
-   }
-
-   bool OnLoadGraphics()
-   {
-      ImageEntry entry;
-      FontEntry fEntry;
-      for(entry = imageCache.first; entry; entry = entry.next)
       {
-         entry.bitmap.MakeDD(displaySystem);
-         if(entry.bitmap && entry.bitmap.alphaBlend)
-         {
-            entry.bitmap.Convert(null, pixelFormat888, null);
-            // entry.bitmap.displaySystem = displaySystem;
-         }
+         block.font = block.parent.font;
+         block.textColor = block.parent.textColor;
       }
-      for(fEntry = fontCache.first; fEntry; fEntry = fEntry.next)
-         fEntry.font = browserWindow.displaySystem.LoadFont(fEntry.face, fEntry.size, fEntry.attribs);
-      return true;
-   }
-   
-   void OnUnloadGraphics()
-   {
-      FontEntry entry;
-      for(entry = fontCache.first; entry; entry = entry.next)
+      else
       {
-         browserWindow.displaySystem.UnloadFont(entry.font);
-         entry.font = null;
+         block.textColor = black;
       }
+
+      for(child = block.subBlocks.first; child; child = child.next)
+         LoadGraphics(child, previous);
    }
 
    void NormalizeSelection(Block * startBlock, int * startSel, Block * endBlock, int * endSel)
@@ -646,8 +696,11 @@ class HTMLView : Window
       Surface surface = display.GetSurface(0,0,null);
       if(surface)
       {
+         Font font;
          if(html.defaultFont.font)
             surface.TextFont(html.defaultFont.font.font);
+
+         font = surface.font;
          for(;block;)
          {
             Block nextBlock;
@@ -656,7 +709,6 @@ class HTMLView : Window
             int left, right;
             int x, maxW;
             int thisLineCentered = centered;
-            Font font = surface.GetFont();
             bool changeLine;
 
             left = LEFT_MARGIN;
@@ -682,12 +734,13 @@ class HTMLView : Window
             maxW = right - left;
 
             newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, &centered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, true, 0 /*y*/, LEFT_MARGIN);
+
             if(thisLineCentered)
                x = Max(left,(left + right - w) / 2);
             else
                x = left;
 
-            surface.TextFont(font);
+            surface.font = font;
 
             PositionLine(this, surface, x - scroll.x, y - scroll.y,
                maxW, newH, block, textPos, nextBlock, nextTextPos, 
@@ -707,13 +760,15 @@ class HTMLView : Window
 
    void Open(char * location, char * firstReferer)
    {
-      HTTPFile f {};
+      HTTPFile f { /*reuseConnection = false*/ };
       char referer[MAX_LOCATION] = "";
       char relocation[MAX_LOCATION];
       bool opened = false;
 
       strcpy(relocation, location);
 
+      // PrintLn("\n\n\nOpening new location: ", location, "\n");
+
       if(strstr(location, "http://") != location)
       {
          if(!FileExists(location))
@@ -781,9 +836,153 @@ class HTMLView : Window
 
       if(opened)
       {
+         bool isHTTP = eClass_IsDerived(f._class, class(HTTPFile));
          void * previous = null;
-         html.Parse(f);
+         bool isImage = false;
+         bool isPlain = isHTTP ? false : true;
+
+         // Handle known types
+         if(isHTTP && f.contentType)
+         {
+            if(strstr(f.contentType, "image/") == f.contentType)
+               isImage = true;
+            else if(strstr(f.contentType, "text/") == f.contentType && strnicmp(f.contentType + 5, "html", 4))
+               isPlain = true;
+         }
+         else
+         {
+            const String imageExt[] = { "jpg", "jpeg", "bmp", "pcx", "png", "gif" };
+            const String htmlExt[] = { "html", "htm", "php" };
+            const String textExt[] = { "c", "h", "ec", "eh", "epj", "cpp", "cxx", "cc", "hpp", "hxx", "hh", "m", "java", "cs", "py", "Makefile", "mk", "cf" };
+            char ext[MAX_EXTENSION];
+            int i;
+            GetExtension(fileName, ext);
+            for(i = 0; i < sizeof(imageExt) / sizeof(imageExt[0]); i++)
+               if(!strcmpi(ext, imageExt[i]))
+               {
+                  isImage = true;
+                  break;
+               }
+
+            for(i = 0; i < sizeof(htmlExt) / sizeof(htmlExt[0]); i++)
+               if(!strcmpi(ext, htmlExt[i]))
+               {
+                  isPlain = false;
+                  break;
+               }
+
+            for(i = 0; i < sizeof(textExt) / sizeof(textExt[0]); i++)
+               if(!strcmpi(ext, textExt[i]))
+               {
+                  isPlain = true;
+                  break;
+               }
+         }
+
+         if(isImage)
+         {
+            Block subBlock;
+            html.body = HTMLFile::AddBlock(html.block, BODY);
+
+            subBlock = HTMLFile::AddBlock(html.body, IMAGE);
+            subBlock.valign = bottom;
+            subBlock.halign = middle;
+            subBlock.src = CopyString(fileName);
+            html.defaultFont.type = FONT;
+            html.defaultFont.face = CopyString("Times New Roman");
+         }
+         else if(isPlain)
+         {
+            uint size;
+            TempFile tmp { };
+            Block subBlock;
+            char * text;
+            int len;
+            String cd = eClass_IsDerived(f._class, class(HTTPFile)) ? f.contentDisposition : null;
+
+            String tmpPath = PrintString("File://", (uintptr)tmp);
+            f.CopyTo(tmpPath);
+            size = tmp.GetSize();
+            tmp.Seek(0, start);
+
+            html.defaultFont.type = FONT;
+            html.defaultFont.face = CopyString("Courier New");
+
+            if(cd)
+            {
+               char fn[MAX_LOCATION];
+               while(GetKeyWordEx(&cd, fn, sizeof(fn), true, false))
+               {
+                  if(!strcmp(fn, "filename") && GetKeyWordEx(&cd, fn, sizeof(fn), true, true))
+                  {
+                     html.titleBlock = HTMLFile::AddBlock(html.block, TITLE);
+                     subBlock = HTMLFile::AddBlock(html.titleBlock, TEXT);
+                     subBlock.text = CopyString(fn);
+                     subBlock.textLen = strlen(fn);
+                  }
+               }
+            }
+
+            html.body = HTMLFile::AddBlock(html.block, BODY);
+            html.block = html.body;
+
+            text = new char[size + 1];
+            len = tmp.Read(text, 1, size);
+            text[len] = 0;
+
+            {
+               int c;
+               char ch;
+               int start = 0;
+               Block textBlock = HTMLFile::AddBlock(html.block, TEXT);
+
+               for(c = 0; ; c++)
+               {
+                  ch = text[c];
+                  if(ch == '\n' || ch == '\r' || !ch)
+                  {
+                     int len = c - start;
+                     textBlock.text = renew textBlock.text char[textBlock.textLen + 1 + len];
+                     memmove(textBlock.text + len, textBlock.text, textBlock.textLen + 1);
+                     memcpy(textBlock.text, text + start, len);
+                     textBlock.textLen += len;
+                     if(!ch) break;
+                     {
+                        Block block { type = BR, parent = textBlock.parent };
+                        Block newBlock { type = TEXT, parent = textBlock.parent };
+
+                        textBlock.parent.subBlocks.Insert(textBlock, block);
+                        textBlock.parent.subBlocks.Insert(block, newBlock);
+
+                        newBlock.textLen = 0;
+                        newBlock.text = new char[1];
+                        newBlock.text[0] = 0;
+
+                        textBlock = newBlock;
+                     }
+                     if(ch == '\r' && text[c+1] == '\n') c++;
+                     start = c + 1;
+                  }
+               }
+
+               html.block = html.block.parent;
+               delete text;
+            }
+            delete tmp;
+            delete tmpPath;
+
+         }
+         else
+         {
+            html.Parse(f);
+            if(html.baseHRef)
+            {
+               delete this.location;
+               this.location = CopyString(html.baseHRef);
+            }
+         }
          LoadGraphics(html.defaultFont, &previous);
+         html.block.font = html.defaultFont.font;
          LoadGraphics(html.block, &previous);
          CreateForms(html.block);
 
@@ -804,7 +1003,10 @@ class HTMLView : Window
          */
          
       }
+      ((GuiApplication)__thisModule.application).Unlock();
+      // PrintLn("At position ", f.Tell(), " for ", fileName);
       delete f;
+      ((GuiApplication)__thisModule.application).Lock();
       NotifyPageOpened(master);
    }
 
@@ -836,6 +1038,7 @@ class HTMLView : Window
          void * previous = null;
          html.Parse(f);
          LoadGraphics(html.defaultFont, &previous);
+         html.block.font = html.defaultFont.font;
          LoadGraphics(html.block, &previous);
          CreateForms(html.block);
 
@@ -964,6 +1167,7 @@ class HTMLView : Window
       int maxH = clientSize.h - BOTTOM_MARGIN;
       OldList leftObjects { };
       OldList rightObjects { };
+      Font font;
 
       AlignedObject object, nextObject;
       int h = 0;
@@ -986,7 +1190,6 @@ class HTMLView : Window
          int left, right;
          int x, maxW;
          int thisLineCentered = centered;
-         Font font = surface.GetFont();
          bool changeLine;
 
          left = LEFT_MARGIN;
@@ -1011,7 +1214,9 @@ class HTMLView : Window
          right = Max(left, right);
          maxW = right - left;
 
+         font = surface.font;
          newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, &centered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
+         surface.font = font;
          if(thisLineCentered)
             x = Max(left,(left + right - w) / 2);
          else
@@ -1110,7 +1315,7 @@ class HTMLView : Window
             int left, right;
             int x, maxW;
             int thisLineCentered = centered;
-            Font font = surface.GetFont();
+            Font font = surface.font;
             bool changeLine;
 
             left = LEFT_MARGIN;
@@ -1141,7 +1346,7 @@ class HTMLView : Window
             else
                x = left;
 
-            surface.TextFont(font);
+            surface.font = font;
 
             if(PickLine(this, surface, x - scroll.x, y - scroll.y, 
                maxW, newH, block, textPos, nextBlock, nextTextPos, 
@@ -1161,6 +1366,17 @@ class HTMLView : Window
          }
          delete surface;
       }
+
+      for(object = leftObjects.last; object; object = nextObject)
+      {
+         nextObject = object.prev;
+         leftObjects.Delete(object);
+      }
+      for(object = rightObjects.last; object; object = nextObject)
+      {
+         nextObject = object.prev;
+         rightObjects.Delete(object);
+      }
       return result;
    }
 
@@ -1184,7 +1400,7 @@ class HTMLView : Window
          }
          if(linkBlock)
          {
-            if(strstr(linkBlock.href, "edit://") == linkBlock.href)
+            if(linkBlock.href && strstr(linkBlock.href, "edit://") == linkBlock.href)
                cursor = ((GuiApplication)__thisModule).GetCursor(iBeam);
             else
                cursor = ((GuiApplication)__thisModule).GetCursor(hand);
@@ -1353,21 +1569,7 @@ class HTMLView : Window
    {
       delete this.location;
 
-      {
-         ImageEntry entry;
-         FontEntry fontEntry;
-         while((entry = imageCache.first))
-         {
-            imageCache.Remove(entry);
-            delete entry;
-         }
-         while((fontEntry = fontCache.first))
-         {
-            fontCache.Remove(fontEntry);
-            delete fontEntry;
-         }
-         html.block.ClearEntries();
-      }
+      html.block.ClearEntries();
    }
 
    property char * location
@@ -1382,4 +1584,13 @@ class HTMLView : Window
       }
       get { return location; }
    }
+
+   property String title
+   {
+      get
+      {
+         String title = html.title;
+         return title ? title : location;
+      }
+   }
 }
index 438339b..d1b64f7 100644 (file)
@@ -1,7 +1,7 @@
 import "HTMLView"
 
-#define MAX_TAG_LEN  204800
-#define MAX_SYMBOL_LEN  1000
+#define MAX_TAG_LEN     256
+#define MAX_SYMBOL_LEN  256
 
 #define WORD_NONE    0
 #define WORD_NORMAL  1
@@ -101,12 +101,40 @@ class Block : struct
    }
 };
 
-static bool GetKeyWordEx(char ** input, char * keyWord, int maxSize, bool treatEqual)
+String ParseURL(String input)
+{
+   int c;
+   char ch;
+   int len = strlen(input);
+   String output = new char[len+1];
+   len = 0;
+   for(c = 0; (ch = input[c]); c++)
+   {
+      if(ch == '%' && isalnum(input[c+1]) && isalnum(input[c+2]))
+      {
+         char hex[3] = { input[c+1], input[c+2], 0 };
+         char * end;
+         int v = (int)strtoul(hex, &end, 16);
+         if(v && end == hex + 2)
+         {
+            output[len++] = (char)v;
+            c += 2;
+            continue;
+         }
+      }
+      output[len++] = ch;
+   }
+   output[len++] = 0;
+   return renew output char[len];
+}
+
+/*static */bool GetKeyWordEx(char ** input, char * keyWord, int maxSize, bool treatEqual, bool acceptSingleQuote)
 {
    char * string = *input;
    char ch;
    int c = 0;
    bool quoted = false, start = true, wasQuoted = false;
+   char quoteChar = 0;
 
    for(; (ch = *string); string++)
    {
@@ -121,8 +149,10 @@ static bool GetKeyWordEx(char ** input, char * keyWord, int maxSize, bool treatE
       {
          if(!quoted && ((ch == ',' || (treatEqual && ch == '=')) || ch == '>') )
             break;
-         else if(ch == '\"' /*|| ch == '\''*/)
+         else if((ch == '\"' || (acceptSingleQuote && ch == '\'')) && (!quoteChar || quoteChar == ch))
          {
+            if(!wasQuoted)
+               quoteChar = ch;
             quoted ^= true;
             wasQuoted = true;
             start = false;
@@ -143,7 +173,7 @@ static bool GetKeyWordEx(char ** input, char * keyWord, int maxSize, bool treatE
 
 static bool GetKeyWord(char ** input, char * keyWord, int maxSize)
 {
-   return GetKeyWordEx(input, keyWord, maxSize, true);
+   return GetKeyWordEx(input, keyWord, maxSize, true, false);
 }
 
 static char * GetString(char * string, char * what, int count)
@@ -164,30 +194,54 @@ static char * GetString(char * string, char * what, int count)
    return string + sc;
 }
 
-static Block AddBlock(Block parent, BlockType type)
+#include <stdio.h>
+
+String EncodeString(String input, int * lenPtr)
 {
-   Block block = Block { parent = parent, type = type };
-   parent.subBlocks.Add(block);
-   return block;
+   if(UTF8Validate(input))
+   {
+      return CopyString(input);
+   }
+   else
+   {
+      int len = strlen(input);
+      String s = new char[len*4+1];
+      len = ISO8859_1toUTF8(input, s, len*4);
+      if(lenPtr) *lenPtr = len;
+      return renew s char[len+1];
+   }
 }
 
-#include <stdio.h>
-
 class HTMLFile
 {
    Block block {};
    Block defaultFont { };
 
    Block body;
+   Block titleBlock;
    ColorAlpha background { 255, white };
+   String baseHRef;
    //Button defaultButton;
 
+   Block ::AddBlock(Block parent, BlockType type)
+   {
+      Block block = Block { parent = parent, type = type };
+      parent.subBlocks.Add(block);
+      return block;
+   }
+
+   ~HTMLFile()
+   {
+      delete baseHRef;
+   }
+
    bool Parse(File f)
    {
+      bool result = true;
       bool insideTag = false;
       char tag[MAX_TAG_LEN];
       char symbol[MAX_SYMBOL_LEN];
-      int tagLen;
+      int tagLen = 0;
       Block block = this.block, subBlock;
       char * text;
       int textLen = 0;
@@ -198,6 +252,7 @@ class HTMLFile
       byte lastCh = ' ';
       bool code = false;
       bool quoted = false;
+      bool lastBR = true;
 
       Block fontBlock = defaultFont;
       fontBlock.type = FONT;
@@ -212,13 +267,14 @@ class HTMLFile
       fontBlock.textColor = black;
       fontBlock.size = 10;
 
-      fontBlock.font = FontEntry { size = fontBlock.size, attribs = fontBlock.attribs, face = CopyString(fontBlock.face) };
-      fontCache.Add(fontBlock.font);
+      /*fontBlock.font = FontEntry { size = fontBlock.size, attribs = fontBlock.attribs, face = CopyString(fontBlock.face) };
+      fontCache.Add(fontBlock.font);*/
 
       background = white;
       
       text = new char[32768*4];
 
+      block.font = fontBlock.font;
       body = block;
       
       // Parse entire file
@@ -227,7 +283,9 @@ class HTMLFile
          byte ch = 0;
          
          f.Getc(&ch);
+#ifdef _DEBUG
          //fwrite(&ch, 1, 1, stdout);
+#endif
          if(commented)
          {
             if((ch == '-' && tagLen < 2) || (ch == '>' && tagLen == 2))
@@ -246,8 +304,10 @@ class HTMLFile
          {
             if(ch == '\"')
                quoted ^= true;
-            if(ch == '<' && !quoted)
+            if(ch == '<' && !quoted && !insideScript && !insideStyle)
+            {
                insideTag++;
+            }
             /*else */if(ch == '>' && !quoted)
             {
                insideTag--;
@@ -283,6 +343,7 @@ class HTMLFile
                      }
                      else if(!strcmpi(keyWord, "img"))
                      {
+                        lastBR = false;
                         subBlock = AddBlock(block, IMAGE);
                         subBlock.valign = bottom;
                         subBlock.halign = middle;
@@ -291,7 +352,7 @@ class HTMLFile
                            GetKeyWord(&string, keyWord, sizeof(keyWord));
                            if(!strcmpi(keyWord, "src"))
                            {
-                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, false);
                               delete subBlock.src;
                               subBlock.src = keyWord[0] ? CopyString(keyWord) : null;
                            }
@@ -345,6 +406,11 @@ class HTMLFile
                            }
                         }
                      }
+                     else if(!strcmpi(keyWord, "title"))
+                     {
+                        block = AddBlock(block, TITLE);
+                        titleBlock = block;
+                     }
                      else if(!strcmpi(keyWord, "body"))
                      {
                         block = AddBlock(block, BODY);
@@ -357,7 +423,7 @@ class HTMLFile
                            if(!strcmpi(keyWord, "bgcolor"))
                            {
                               GetKeyWord(&string, keyWord, sizeof(keyWord));
-                              background = strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16);
+                              background = !strcmpi(keyWord, "#fff") ?  white : strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16);
                               if(keyWord[0] != '#' || strlen(keyWord) <= 7)
                                  background |= 0xFF000000;
                            }
@@ -369,10 +435,32 @@ class HTMLFile
                            }
                         }
                      }
-                     else if(!strcmpi(keyWord, "br"))
+                     else if(!strcmpi(keyWord, "br") || (!lastBR && (!strcmpi(keyWord, "div") || !strcmpi(keyWord, "li"))))
                      {
-                        subBlock = AddBlock(block, BR);
-                        lastCh = ' ';
+                        if(!lastBR || (lastCh && lastCh != ' '))
+                        {
+                           subBlock = AddBlock(block, BR);
+                           lastCh = ' ';
+                           lastBR = true;
+                        }
+                     }
+                     else if(!strcmpi(keyWord, "/ul"))
+                     {
+                        lastBR = false;
+                     }
+                     else if(!strcmpi(keyWord, "/ul"))
+                     {
+                        lastBR = false;
+                     }
+                     else if(!strcmpi(keyWord, "/div"))
+                     {
+                        if(!lastBR)
+                        {
+                           subBlock = AddBlock(block, BR);
+                           lastBR = true;
+                        }
+                        else
+                           lastBR = false;
                      }
                      else if(!strcmpi(keyWord, "code"))
                      {
@@ -389,6 +477,17 @@ class HTMLFile
                         || !strcmpi(keyWord, "strong") || !strcmpi(keyWord, "em") || 
                         !strcmpi(keyWord, "h1") || !strcmpi(keyWord, "h2") || !strcmpi(keyWord, "h3"))
                      {
+                        if((!strcmpi(keyWord, "h1") || !strcmpi(keyWord, "h2") || !strcmpi(keyWord, "h3")))
+                        {
+                           if(!lastBR || (lastCh && lastCh != ' '))
+                           {
+                              if(!lastBR)
+                                 subBlock = AddBlock(block, BR);
+                              subBlock = AddBlock(block, BR);
+                              lastBR = true;
+                           }
+                           lastCh = ' ';
+                        }
                         subBlock = AddBlock(block, FONT);
                         subBlock.attribs = fontBlock.attribs;
                         if(!strcmpi(keyWord, "font"))
@@ -479,17 +578,23 @@ class HTMLFile
                              !strcmpi(keyWord, "/h2") ||
                              !strcmpi(keyWord, "/h3"))
                      {
-                        if(block.type == FONT)
+                        /*while(block.type != FONT && block.parent && block.parent.type != BODY)
+                           block = block.parent;*/
+                        if(block.type == FONT || block.type == ANCHOR)
                         {
                            fontBlock = block.prevFont;
                            block = block.parent;
                         }
+                        if(!lastBR && (!strcmpi(keyWord, "/h1") || !strcmpi(keyWord, "/h2") || !strcmpi(keyWord, "/h3")))
+                        {
+                           subBlock = AddBlock(block, BR);
+                           lastBR = true;
+                        }
                      }
                      else if(!strcmpi(keyWord, "a"))
                      {
                         int textDecoration = 0;
-                        subBlock = AddBlock(block, ANCHOR);
-                        subBlock.attribs = fontBlock.attribs;
+                        Block anchor { type = ANCHOR, parent = block };
 
                         for(;string[0];)
                         {
@@ -497,15 +602,15 @@ class HTMLFile
 
                            if(!strcmpi(keyWord, "name"))
                            {
-                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
-                              delete subBlock.anchor;
-                              subBlock.anchor = CopyString(keyWord);
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, false);
+                              delete anchor.anchor;
+                              anchor.anchor = CopyString(keyWord);
                            }
                            else if(!strcmpi(keyWord, "href"))
                            {
-                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
-                              delete subBlock.href;
-                              subBlock.href = CopyString(keyWord);
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, true);
+                              delete anchor.href;
+                              anchor.href = CopyString(keyWord);
                               if(!textDecoration)
                                  textDecoration = 1;
                            }
@@ -513,22 +618,46 @@ class HTMLFile
                            {
                               //for(;string[0];)
                               {
-                                 GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
+                                 GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, false);
                                  if(strstr(keyWord, "text-decoration:") && strstr(keyWord, "none;"))
                                     textDecoration = 2;
                               }
                            }
                         }
-                        subBlock.attribs |= FONT_BOLD;
-                        if(textDecoration == 1) subBlock.attribs |= FONT_UNDERLINE;
+
+                        if(anchor.href && (/*lastBR || */isalnum(lastCh)))
+                        {
+                           subBlock = AddBlock(block, TEXT);
+                           subBlock.text = CopyString("  ");
+                           subBlock.textLen = 2;
+                           subBlock.prevFont = fontBlock;
+                        }
+                        subBlock = anchor;
+                        block.subBlocks.Add(subBlock);
+
+                        subBlock.attribs = fontBlock.attribs | FONT_BOLD;
                         delete subBlock.face;
                         subBlock.face = CopyString(fontBlock.face);
                         subBlock.size = fontBlock.size;
                         subBlock.textColor = Color { 85,85,255 };
                         subBlock.prevFont = fontBlock;
+                        if(textDecoration == 1) subBlock.attribs |= FONT_UNDERLINE;
                         fontBlock = subBlock;
                         block = subBlock;
+
+                        lastCh = 0;
                      }
+                     /*else if(!strcmpi(keyWord, "/span"))
+                     {
+                        if(isalnum(lastCh))
+                        {
+                           subBlock = AddBlock(block, TEXT);
+                           subBlock.text = CopyString("  ");
+                           subBlock.textLen = 2;
+                           subBlock.prevFont = block.parent.prevFont;
+                        }
+                        lastCh = 0;
+                     }*/
                      else if(!strcmpi(keyWord, "/a"))
                      {
                         if(block.type == ANCHOR)
@@ -555,7 +684,7 @@ class HTMLFile
                         if(insideStyle)
                            insideStyle--;
                      }
-                     else if(!strcmpi(keyWord, "input"))
+                     else if(!strcmpi(keyWord, "input") || !strcmpi(keyWord, "button"))
                      {
                         subBlock = AddBlock(block, INPUT);
                         for(;string[0];)
@@ -564,12 +693,12 @@ class HTMLFile
 
                            if(!strcmpi(keyWord, "type"))
                            {
-                              GetKeyWord(&string, keyWord, sizeof(keyWord));
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), true, true);
                               if(!strcmpi(keyWord, "text"))
                               {
                                  subBlock.inputType = InputType::text;
                               }
-                              else if(!strcmpi(keyWord, "submit"))
+                              else if(!strcmpi(keyWord, "submit") || !strcmpi(keyWord, "image"))
                               {
                                  subBlock.inputType = submit;
                               }
@@ -577,6 +706,10 @@ class HTMLFile
                               {
                                  subBlock.inputType = radio;
                               }
+                              else if(!strcmpi(keyWord, "checkbox"))
+                              {
+                                 subBlock.inputType = checkbox;
+                              }
                               else if(!strcmpi(keyWord, "hidden"))
                               {
                                  subBlock.inputType = hidden;
@@ -586,15 +719,20 @@ class HTMLFile
                            }
                            else if(!strcmpi(keyWord, "size"))
                            {
-                              int size;
                               GetKeyWord(&string, keyWord, sizeof(keyWord));
-                              size = atoi(keyWord);
+                              subBlock.size = atoi(keyWord);
+                           }
+                           else if(!strcmpi(keyWord, "maxlength"))
+                           {
+                              int maxlength;
+                              GetKeyWord(&string, keyWord, sizeof(keyWord));
+                              maxlength = atoi(keyWord);
                            }
                            else if(!strcmpi(keyWord, "value"))
                            {
-                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, true);
                               delete subBlock.value;
-                              subBlock.value = CopyString(keyWord);
+                              subBlock.value = EncodeString(keyWord, null);
                            }
                            else if(!strcmpi(keyWord, "name"))
                            {
@@ -602,6 +740,12 @@ class HTMLFile
                               delete subBlock.name;
                               subBlock.name = CopyString(keyWord);
                            }
+                           else if(!strcmpi(keyWord, "src"))
+                           {
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, false);
+                              delete subBlock.src;
+                              subBlock.src = keyWord[0] ? CopyString(keyWord) : null;
+                           }
                         }
                      }
                      else if(!strcmpi(keyWord, "form"))
@@ -613,7 +757,7 @@ class HTMLFile
 
                            if(!strcmpi(keyWord, "action"))
                            {
-                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false);
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, false);
                               delete subBlock.action;
                               subBlock.action = CopyString(keyWord);
                            }
@@ -639,6 +783,20 @@ class HTMLFile
                            block = block.parent;
                         }
                      }
+                     else if(!strcmpi(keyWord, "base"))
+                     {
+                        while(string[0])
+                        {
+                           GetKeyWord(&string, keyWord, sizeof(keyWord));
+
+                           if(!strcmpi(keyWord, "href"))
+                           {
+                              GetKeyWordEx(&string, keyWord, sizeof(keyWord), false, true);
+                              delete baseHRef;
+                              baseHRef = ParseURL(keyWord);
+                           }
+                        }
+                     }
                      else if(!strcmpi(keyWord, "table"))
                      {
                         lastCh = ' ';
@@ -678,7 +836,7 @@ class HTMLFile
                            else if(!strcmpi(keyWord, "bgcolor"))
                            {
                               GetKeyWord(&string, keyWord, sizeof(keyWord));
-                              subBlock.bgColor = 0xFF000000 | strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16);
+                              subBlock.bgColor = !strcmpi(keyWord, "#fff") ? white : (0xFF000000 | strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16));
                            }
                            else if(!strcmpi(keyWord, "align"))
                            {
@@ -705,17 +863,17 @@ class HTMLFile
                         if(block.type == TD)
                         {
                            block = block.parent;
-                           lastCh = ' ';
+                           lastCh = 0;//' ';
                         }
                         if(block.type == TR)
                         {
                            block = block.parent;
-                           lastCh = ' ';
+                           lastCh = 0;//' ';
                         }
                         if(block.type == TABLE)
                         {
                            block = block.parent;
-                           lastCh = ' ';
+                           lastCh = 0;//' ';
                         }
                      }
                      else if(!strcmpi(keyWord, "tr"))
@@ -843,7 +1001,7 @@ class HTMLFile
                               else if(!strcmpi(keyWord, "bgcolor"))
                               {
                                  GetKeyWord(&string, keyWord, sizeof(keyWord));
-                                 subBlock.bgColor = 0xFF000000 | strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16);
+                                 subBlock.bgColor = !strcmpi(keyWord, "#fff") ? white : (0xFF000000 |strtol((keyWord[0] == '#') ? (keyWord+1) : keyWord, null, 16));
                               }
                               else if(!strcmpi(keyWord, "valign"))
                               {
@@ -886,7 +1044,7 @@ class HTMLFile
                         if(block.type == TD)
                         {
                            block = block.parent;
-                           lastCh = ' ';
+                           lastCh = 0;//' ';
                         }
                      }
                      else if(!strcmpi(keyWord, "/html"))
@@ -895,14 +1053,27 @@ class HTMLFile
                }
                else
                {
-                  tag[tagLen++] = ch;
-                  tag[tagLen] = '\0';
+                  if(tagLen < MAX_TAG_LEN-1)
+                  {
+                     tag[tagLen++] = ch;
+                     tag[tagLen] = '\0';
+                  }
                }
             }
             else
             {
-               tag[tagLen++] = ch;
-               tag[tagLen] = '\0';
+               if((insideScript || insideStyle) && !tagLen && ch != '/')
+               {
+                  insideTag = false;
+               }
+               else
+               {
+                  if(tagLen < MAX_TAG_LEN-1)
+                  {
+                     tag[tagLen++] = ch;
+                     tag[tagLen] = '\0';
+                  }
+               }
             }
             if(!strcmp(tag, "!--"))
             {
@@ -916,31 +1087,34 @@ class HTMLFile
          {
             if(ch == '<')
             {
-               if(textLen)
+               if(!insideScript && !insideStyle)
                {
-                  if(block.type == TABLE)
+                  if(textLen)
                   {
-                     subBlock = AddBlock(block, TR);
-                     block = subBlock;
-                  }
-                  if(block.type == TR)
-                  {
-                     subBlock = AddBlock(block, TD);
-                     subBlock.span = subBlock.rowSpan = 1;
-                     subBlock.valign = block.valign;
-                     subBlock.halign = block.halign;
-                     block = subBlock;
-                  }
-
-                  subBlock = AddBlock(block, TEXT);
-                  delete subBlock.text;
-                  subBlock.text = CopyString(text);
-                  subBlock.textLen = textLen;
-
+                     if(block.type == TABLE)
+                     {
+                        subBlock = AddBlock(block, TR);
+                        block = subBlock;
+                     }
+                     if(block.type == TR)
+                     {
+                        subBlock = AddBlock(block, TD);
+                        subBlock.span = subBlock.rowSpan = 1;
+                        subBlock.valign = block.valign;
+                        subBlock.halign = block.halign;
+                        block = subBlock;
+                     }
 
-                  textLen = 0;
-                  text[0] = '\0';
+                     subBlock = AddBlock(block, TEXT);
+                     delete subBlock.text;
+                     subBlock.text = EncodeString(text, &textLen);
+                     subBlock.textLen = textLen;
+                     if(block.type != TITLE)
+                        lastBR = false;
 
+                     textLen = 0;
+                     text[0] = '\0';
+                  }
                }
 
                insideTag = true;
@@ -954,7 +1128,9 @@ class HTMLFile
                   {
                      unichar unicode = 0;
                      char utf8[5];
-                     if(!strcmpi(symbol, "nbsp")) 
+                     if(symbol[0] == '#' && symbol[1] == 'x')
+                        unicode = strtol(symbol+2, null, 16);
+                     else if(!strcmpi(symbol, "nbsp")) 
                         unicode = ' ';
                      else if(!strcmpi(symbol, "copy")) 
                         unicode ='©';
@@ -971,7 +1147,7 @@ class HTMLFile
                      else if(!strcmpi(symbol, "acirc"))
                         unicode = 'â';
                      else if(!strcmpi(symbol, "ocirc"))
-                        unicode = 'ô';                     
+                        unicode = 'ô';
                      if(unicode)
                      {
                         int len = UTF32toUTF8Len(&unicode, 1, utf8, 5);
@@ -995,8 +1171,11 @@ class HTMLFile
                   }
                   else
                   {
-                     symbol[symbolLen++] = ch;
-                     symbol[symbolLen] = '\0';
+                     if(symbolLen < MAX_SYMBOL_LEN-1)
+                     {
+                        symbol[symbolLen++] = ch;
+                        symbol[symbolLen] = '\0';
+                     }
                   }
                }
                else
@@ -1026,7 +1205,7 @@ class HTMLFile
 
                subBlock = AddBlock(block, TEXT);
                delete subBlock.text;
-               subBlock.text = CopyString(text);
+               subBlock.text = EncodeString(text, &textLen);
                subBlock.textLen = textLen;
                textLen = 0;
                text[0] = '\0';
@@ -1040,6 +1219,19 @@ class HTMLFile
          byte ch = 0;
          f.Getc(&ch);
       }*/
-      return true;
+      return result;
+   }
+
+   property String title
+   {
+      get
+      {
+         if(titleBlock && titleBlock.subBlocks.first && ((Block)titleBlock.subBlocks.first).type == TEXT)
+         {
+            Block t = titleBlock.subBlocks.first;
+            return t.text;            
+         }
+         return null;
+      }
    }
 }
index 7d09e8f..b8a9917 100644 (file)
@@ -31,26 +31,35 @@ Block GetNextBlock(Block block)
       {
          if(block.type == FONT || block.type == ANCHOR)
          {
-            surface.TextFont(block.prevFont.font.font);
+            surface.TextFont(block.parent.font.font);
             if(flags.render)
-               surface.SetForeground(block.prevFont.textColor);
+               surface.SetForeground(block.parent.textColor);
          }
          block = block.next;
          break;
       }
 
+      //if(block)
+      {
+         if(block.type == FONT || block.type == ANCHOR)
+         {
+            surface.TextFont(block.parent.font.font);
+            if(flags.render)
+               surface.SetForeground(block.parent.textColor);
+         }
+      }
       block = block.parent;
 
       // Getting out of a block
       if(block)
       {
-         if(block.type == FONT || block.type == ANCHOR)
+         /*if(block.type == FONT || block.type == ANCHOR)
          {
             surface.TextFont(block.prevFont.font.font);
             if(flags.render)
                surface.SetForeground(block.prevFont.textColor);
          }
-         else if(block.type == CENTER)
+         else */if(block.type == CENTER)
          {
             if(centered)
                (*centered)--;
@@ -106,7 +115,7 @@ int ComputeLine(Surface surface, Block startBlock, int startTextPos, Block * nex
             if(block.window)
             {
                width += block.window.size.w;
-               height = Max(height, block.window.size.h);
+               height = Max(height, Max(26, block.window.size.h));
             }
             break;
          }
@@ -161,7 +170,6 @@ int ComputeLine(Surface surface, Block startBlock, int startTextPos, Block * nex
             surface.TextExtent(" ", 1, null, &th);
             height = Max(height, th);
 
-
             for(; textPos<block.textLen && !lineComplete;)
             {
                int w;
@@ -231,7 +239,9 @@ int ComputeLine(Surface surface, Block startBlock, int startTextPos, Block * nex
             }
             else if(block.halign == left || block.halign == right)
             {
+               Font font = surface.font;
                ComputeTable(surface, block, textPos, &width, &height, maxW, maxH, flags, y + sy, x + sx);
+               surface.font = font;
                x += width;
             
                *nextBlock = NextBlockUp(surface, block, centered, flags);
@@ -252,7 +262,9 @@ int ComputeLine(Surface surface, Block startBlock, int startTextPos, Block * nex
             }
             else
             {
+               Font font = surface.font;
                ComputeTable(surface, block, textPos, &width, &height, maxW, maxH, flags, y + sy, x + sx);
+               surface.font = font;
                lineComplete = true;
                *nextBlock = NextBlockUp(surface, block, centered, flags);
                *nextTextPos = 0;
index d1cdc37..a105afb 100644 (file)
@@ -863,8 +863,7 @@ static void RenderCell(HTMLView browser, Surface surface, Block cell, int cellX,
       int left, right;
       int maxW;
       bool changeLine;
-
-      void * font = surface.GetFont();
+      Font font;
 
       // Compute aligned objects
       left = cellX + table.cellPadding; // Add cell border/margins here?
@@ -889,9 +888,9 @@ static void RenderCell(HTMLView browser, Surface surface, Block cell, int cellX,
       right = Max(left, right);
       maxW = right - left;
 
+      font = surface.font;
       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
-
-      surface.TextFont(font);
+      surface.font = font;
 
       if(cell.halign == middle || thisLineCentered)
       {
@@ -1067,7 +1066,7 @@ static bool PickCell(HTMLView browser, Surface surface, Block cell, int cellX, i
       int maxW;
       bool changeLine;
 
-      void * font = surface.GetFont();
+      Font font;
 
       // Compute aligned objects
       left = cellX + table.cellPadding; // Add cell border/margins here?
@@ -1092,9 +1091,11 @@ static bool PickCell(HTMLView browser, Surface surface, Block cell, int cellX, i
       right = Max(left, right);
       maxW = right - left;
 
+      font = surface.font;
       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
+      surface.font = font; 
 
-      surface.TextFont(font);
+      //surface.TextFont(font);
 
       if(cell.halign == middle || thisLineCentered)
       {
@@ -1262,7 +1263,7 @@ static void PositionCell(HTMLView browser, Surface surface, Block cell, int cell
       int maxW;
       bool changeLine;
 
-      void * font = surface.GetFont();
+      Font font;
 
       // Compute aligned objects
       left = cellX + table.cellPadding; // Add cell border/margins here?
@@ -1287,9 +1288,11 @@ static void PositionCell(HTMLView browser, Surface surface, Block cell, int cell
       right = Max(left, right);
       maxW = right - left;
 
+      font = surface.font;
       newLineH = ComputeLine(surface, block, textPos, &nextCellBlock, &nextCellPos, &centered, &lineW, maxW, maxH, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
+      surface.font = font;
 
-      surface.TextFont(font);
+      // surface.TextFont(font);
 
       if(cell.halign == middle || thisLineCentered)
       {