/* * Returns the hash entry at position pos * Null is pos is invalid or there is no entry at this position */ hash_entry Moca_EntryAtPos(hash_map map, unsigned int pos) { if(!map || pos >= map->tableSize || tableElt(map,pos)->next==MOCA_HASHMAP_UNUSED) return NULL; return tableElt(map,pos); }
/* * Returns -1 if key is not in map * the position of key in the map if it is present */ int Moca_PosInMap(hash_map map,hash_entry e) { unsigned long h; int ind=0; if(!map) return -1; h=hash_ptr(e->key, map->hash_bits); ind=map->hashs[h]; while(ind>=0 && map->comp(tableElt(map,ind),e)!=0 ) ind=tableElt(map,ind)->next; return ind; }
// Clear map, after this call, map is still usable void Moca_ClearMap(hash_map map) { unsigned int i; unsigned long h; if(!map) return; for(i=0;i<map->nbentry;++i) { h=hash_ptr(tableElt(map,i)->key, map->hash_bits); map->hashs[h]=MOCA_HASHMAP_END; tableElt(map,i)->next=MOCA_HASHMAP_UNUSED; } }
/* * Find the first available entry from pos * Returns the entry on success * NULL if there is no more entry * After the call to Memmap_NextEntryPos, pos is the position of the returned * entry +1 * This function can be used as an iterator */ hash_entry Moca_NextEntryPos(hash_map map, unsigned int *pos) { unsigned int i=*pos; MOCA_DEBUG_PRINT("Moca Searching element in map %p after %d /%d\n", map, i, Moca_NbElementInMap(map)); while(i< map->tableSize && tableElt(map,i)->next==MOCA_HASHMAP_UNUSED) ++i; *pos=i+1; MOCA_DEBUG_PRINT("Moca found %p at %d\n", i>=map->tableSize?NULL:tableElt(map,i),i); if(i >=map->tableSize) return NULL; return tableElt(map,i); }
/* * Return the hash entry corresponding to key, * NULL if key is not in the map */ hash_entry Moca_EntryFromKey(hash_map map, hash_entry e) { unsigned long h; int ind=0; if(!map || !e) return NULL; h=hash_ptr(e->key, map->hash_bits); ind=map->hashs[h]; while(ind>=0 && map->comp(tableElt(map,ind),e)!=0 ) ind=tableElt(map,ind)->next; if(ind >=0) return tableElt(map,ind); return NULL; }
hash_map Moca_InitHashMap(unsigned long hash_bits, int nb_elt, size_t elt_size, comp_fct_t comp) { unsigned int i; hash_map map=kmalloc(sizeof(struct _hash_map), GFP_ATOMIC); if(!map) return NULL; map->hash_bits=hash_bits; map->size=1<<hash_bits; map->tableSize=nb_elt; map->nbentry=0; map->elt_size=elt_size; if(comp) map->comp=comp; else map->comp=&Moca_DefaultHashMapComp; MOCA_DEBUG_PRINT("Moca allocationg hash size %lu\n", map->size); if(!(map->hashs=kmalloc(sizeof(int)*map->size,GFP_ATOMIC))) { kfree(map); return NULL; } for(i=0;i<map->size;++i) map->hashs[i]=MOCA_HASHMAP_END; if(!(map->table=kcalloc(map->tableSize,elt_size,GFP_ATOMIC))) { kfree(map->hashs); kfree(map); return NULL; } for(i=0;i<map->tableSize;++i) tableElt(map,i)->next=MOCA_HASHMAP_UNUSED; return map; }
unsigned int Moca_FindNextAvailPosMap(hash_map map) { unsigned int i=0; while(i< map->tableSize && tableElt(map,i)->next!=MOCA_HASHMAP_UNUSED) ++i; return i; }
hash_entry Moca_RemoveFromMap(hash_map map,hash_entry e) { unsigned long h; int ind, ind_prev=MOCA_HASHMAP_END; if(!map) return NULL; MOCA_DEBUG_PRINT("Moca removing %p from %p\n", e->key, map); h=hash_ptr(e->key, map->hash_bits); ind=map->hashs[h]; while(ind>=0 && map->comp(tableElt(map,ind),e)!=0 ) { ind_prev=ind; ind=tableElt(map,ind)->next; } MOCA_DEBUG_PRINT("Moca removing %p from %p ind %d prev %d\n", e->key, map, ind, ind_prev); //key wasn't in map if(ind<0 ) return NULL; //Remove from list if(ind_prev>=0) { tableElt(map,ind_prev)->next=tableElt(map,ind)->next; } else { map->hashs[h]=tableElt(map,ind)->next; } tableElt(map,ind)->next=MOCA_HASHMAP_UNUSED; --map->nbentry; MOCA_DEBUG_PRINT("Moca removing %p from %p ind %d ok\n", e->key, map, ind); return tableElt(map,ind); }
PRBool nsHTMLTableAccessible::HasDescendant(const nsAString& aTagName, PRBool aAllowEmpty) { nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent)); NS_ENSURE_TRUE(tableElt, PR_FALSE); nsCOMPtr<nsIDOMNodeList> nodeList; tableElt->GetElementsByTagName(aTagName, getter_AddRefs(nodeList)); NS_ENSURE_TRUE(nodeList, PR_FALSE); nsCOMPtr<nsIDOMNode> foundItem; nodeList->Item(0, getter_AddRefs(foundItem)); if (!foundItem) return PR_FALSE; if (aAllowEmpty) return PR_TRUE; // Make sure that the item we found has contents and either has multiple // children or the found item is not a whitespace-only text node. nsCOMPtr<nsIContent> foundItemContent = do_QueryInterface(foundItem); if (foundItemContent->GetChildCount() > 1) return PR_TRUE; // Treat multiple child nodes as non-empty nsIContent *innerItemContent = foundItemContent->GetChildAt(0); if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace()) return PR_TRUE; // If we found more than one node then return true not depending on // aAllowEmpty flag. // XXX it might be dummy but bug 501375 where we changed this addresses // performance problems only. Note, currently 'aAllowEmpty' flag is used for // caption element only. On another hand we create accessible object for // the first entry of caption element (see // nsHTMLTableAccessible::CacheChildren). nodeList->Item(1, getter_AddRefs(foundItem)); return !!foundItem; }
/* * Insert key in map * Returns A pointer to the hash_entry corresponding to key * Null in case of error * status is set to: * The position of hash_entry in case of success * One of the following in case of errors: * MOCA_HASHMAP_ALREADY_IN_MAP * MOCA_HASHMAP_FULL * MOCA_HASHMAP_ERROR */ hash_entry Moca_AddToMap(hash_map map, hash_entry e, int *status) { unsigned long h; int ind=0; unsigned int nextPos; if(!map) { *status=MOCA_HASHMAP_ERROR; return NULL; } if(map->nbentry==map->tableSize) { *status=MOCA_HASHMAP_FULL; return NULL; } //Do the insertion nextPos=Moca_FindNextAvailPosMap(map); MOCA_DEBUG_PRINT("Moca inserting %p ind %d/%lu total %d\n", e->key,nextPos,map->tableSize, map->nbentry); if(nextPos >= map->tableSize) { *status=MOCA_HASHMAP_ERROR; Moca_Panic("Moca hashmap BUG in AddToMap"); return NULL; } //Update the link h=hash_ptr(e->key, map->hash_bits); ind=map->hashs[h]; //TODO refactor here if(ind<0) { memcpy(tableElt(map,nextPos),e,map->elt_size); tableElt(map,nextPos)->next=MOCA_HASHMAP_END; map->hashs[h]=nextPos; } else { while(map->comp(tableElt(map,ind),e)!=0 && tableElt(map,ind)->next>=0) ind=tableElt(map,ind)->next; if(map->comp(tableElt(map,ind),e)==0) { MOCA_DEBUG_PRINT("Moca %p already in map %p\n", e->key, map); *status=MOCA_HASHMAP_ALREADY_IN_MAP; //This seems useless tableElt(map,nextPos)->key=NULL; return tableElt(map,ind); } MOCA_DEBUG_PRINT("Moca collision in map %p key %p\n", map, e->key); //TODO: Use Memcpy memcpy(tableElt(map,nextPos),e,map->elt_size); tableElt(map,nextPos)->next=MOCA_HASHMAP_END; tableElt(map,ind)->next=nextPos; } ++map->nbentry; MOCA_DEBUG_PRINT("Moca Inserted %p in map %p\n", e->key, map); *status=nextPos; return tableElt(map,nextPos); }
NS_IMETHODIMP nsHTMLTableAccessible::IsProbablyForLayout(PRBool *aIsProbablyForLayout) { // Implement a heuristic to determine if table is most likely used for layout // XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells // at the beginning or end of a row/col, and especially when they occur at the edge of a table? // XXX expose this info via object attributes to AT-SPI // XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC // This will allow release trunk builds to be used by testers to refine the algorithm // Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release #ifdef SHOW_LAYOUT_HEURISTIC #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \ { *aIsProbablyForLayout = isLayout; \ mLayoutHeuristic = isLayout ? NS_LITERAL_STRING("layout table: ") : NS_LITERAL_STRING("data table: "); \ mLayoutHeuristic += NS_LITERAL_STRING(heuristic); return NS_OK; } #else #define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { *aIsProbablyForLayout = isLayout; return NS_OK; } #endif *aIsProbablyForLayout = PR_FALSE; if (IsDefunct()) return NS_ERROR_FAILURE; nsDocAccessible *docAccessible = GetDocAccessible(); if (docAccessible) { PRUint32 state, extState; docAccessible->GetState(&state, &extState); if (extState & nsIAccessibleStates::EXT_STATE_EDITABLE) { // Need to see all elements while document is being edited RETURN_LAYOUT_ANSWER(PR_FALSE, "In editable document"); } } // Check to see if an ARIA role overrides the role from native markup, // but for which we still expose table semantics (treegrid, for example). PRBool hasNonTableRole = (nsAccUtils::Role(this) != nsIAccessibleRole::ROLE_TABLE); if (hasNonTableRole) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute"); } if (mContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) { // Role attribute is present, but overridden roles have already been dealt with. // Only landmarks and other roles that don't override the role from native // markup are left to deal with here. RETURN_LAYOUT_ANSWER(PR_FALSE, "Has role attribute, weak role, and role is table"); } // Check for legitimate data table elements or attributes nsAutoString summary; if ((mContent->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::summary, summary) && !summary.IsEmpty()) || HasDescendant(NS_LITERAL_STRING("caption"), PR_FALSE) || HasDescendant(NS_LITERAL_STRING("th")) || HasDescendant(NS_LITERAL_STRING("thead")) || HasDescendant(NS_LITERAL_STRING("tfoot")) || HasDescendant(NS_LITERAL_STRING("colgroup"))) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has caption, summary, th, thead, tfoot or colgroup -- legitimate table structures"); } if (HasDescendant(NS_LITERAL_STRING("table"))) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has a nested table within it"); } // If only 1 column or only 1 row, it's for layout PRInt32 columns, rows; GetColumnCount(&columns); if (columns <=1) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 column"); } GetRowCount(&rows); if (rows <=1) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has only 1 row"); } // Check for many columns if (columns >= 5) { RETURN_LAYOUT_ANSWER(PR_FALSE, ">=5 columns"); } // Now we know there are 2-4 columns and 2 or more rows // Check to see if there are visible borders on the cells // XXX currently, we just check the first cell -- do we really need to do more? nsCOMPtr<nsIDOMElement> cellElement; nsresult rv = GetCellAt(0, 0, *getter_AddRefs(cellElement)); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); nsCOMPtr<nsIContent> cellContent(do_QueryInterface(cellElement)); NS_ENSURE_TRUE(cellContent, NS_ERROR_FAILURE); nsIFrame *cellFrame = cellContent->GetPrimaryFrame(); if (!cellFrame) { return NS_OK; } nsMargin border; cellFrame->GetBorder(border); if (border.top && border.bottom && border.left && border.right) { RETURN_LAYOUT_ANSWER(PR_FALSE, "Has nonzero border-width on table cell"); } /** * Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward */ // Check for styled background color across the row // Alternating background color is a common way nsCOMPtr<nsIDOMNodeList> nodeList; nsCOMPtr<nsIDOMElement> tableElt(do_QueryInterface(mContent)); tableElt->GetElementsByTagName(NS_LITERAL_STRING("tr"), getter_AddRefs(nodeList)); NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE); PRUint32 length; nodeList->GetLength(&length); nsAutoString color, lastRowColor; for (PRUint32 rowCount = 0; rowCount < length; rowCount ++) { nsCOMPtr<nsIDOMNode> rowNode; nodeList->Item(rowCount, getter_AddRefs(rowNode)); nsCOMPtr<nsIContent> rowContent(do_QueryInterface(rowNode)); nsCOMPtr<nsIDOMCSSStyleDeclaration> styleDecl = nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), rowContent); NS_ENSURE_TRUE(styleDecl, NS_ERROR_FAILURE); lastRowColor = color; styleDecl->GetPropertyValue(NS_LITERAL_STRING("background-color"), color); if (rowCount > 0 && PR_FALSE == lastRowColor.Equals(color)) { RETURN_LAYOUT_ANSWER(PR_FALSE, "2 styles of row background color, non-bordered"); } } // Check for many rows const PRInt32 kMaxLayoutRows = 20; if (rows > kMaxLayoutRows) { // A ton of rows, this is probably for data RETURN_LAYOUT_ANSWER(PR_FALSE, ">= kMaxLayoutRows (20) and non-bordered"); } // Check for very wide table nsAutoString styledWidth; GetComputedStyleValue(EmptyString(), NS_LITERAL_STRING("width"), styledWidth); if (styledWidth.EqualsLiteral("100%")) { RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns and 100% width"); } if (styledWidth.Find(NS_LITERAL_STRING("px"))) { // Hardcoded in pixels nsIFrame *tableFrame = GetFrame(); NS_ENSURE_TRUE(tableFrame , NS_ERROR_FAILURE); nsSize tableSize = tableFrame->GetSize(); nsDocAccessible *docAccessible = GetDocAccessible(); NS_ENSURE_TRUE(docAccessible, NS_ERROR_FAILURE); nsIFrame *docFrame = docAccessible->GetFrame(); NS_ENSURE_TRUE(docFrame , NS_ERROR_FAILURE); nsSize docSize = docFrame->GetSize(); if (docSize.width > 0) { PRInt32 percentageOfDocWidth = (100 * tableSize.width) / docSize.width; if (percentageOfDocWidth > 95) { // 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width // Probably for layout RETURN_LAYOUT_ANSWER(PR_TRUE, "<=4 columns, width hardcoded in pixels and 95% of document width"); } } } // Two column rules if (rows * columns <= 10) { RETURN_LAYOUT_ANSWER(PR_TRUE, "2-4 columns, 10 cells or less, non-bordered"); } if (HasDescendant(NS_LITERAL_STRING("embed")) || HasDescendant(NS_LITERAL_STRING("object")) || HasDescendant(NS_LITERAL_STRING("applet")) || HasDescendant(NS_LITERAL_STRING("iframe"))) { RETURN_LAYOUT_ANSWER(PR_TRUE, "Has no borders, and has iframe, object, applet or iframe, typical of advertisements"); } RETURN_LAYOUT_ANSWER(PR_FALSE, "no layout factor strong enough, so will guess data"); }