Joins are not done in an order based on inner vs outer, but rather based on what the optimizer thinks will result in the query being executed most quickly. The details will vary between databases. But basically, the query optimizer tries to optimize the use of indexes.
Suppose you had this query:
select a.foo, b.bar
from a
join b on b.b_id=a.b_id
where a.some_number=42;
Now suppose that you have a unique index on b.b_id but no index on a.some_number.
The query optimizer then has two choices: It could do a full-file sequential read on b, and then for each b do a full-file sequential read on a looking for a match on b_id and some_number=42. That is read a^b records. Or it could do a full-file sequential read on a looking for some_number=42, then for each a it could use the index to quickly find the record from b with matching b_id. That is, read a*2 records. Well obviously the second plan is much better, so that's what it will choose.
As you add more tables the calculation becomes more complicated, but the principle is the same. Joins that result in a quick index read using values found in other tables will be done later, after the other tables have been read. Tables that must be read sequentially no matter what, or where the read is based on constants rather than values from other records, are generally read first.